Forum Discussion

BinaryMadman's avatar
13 years ago

Need help with slightly modified Scroll SDK example

I'm almost done with my pet BrightScript project (a folder-based comic viewer). I am able to generate a list of image files on an external drive then display them to the Screen one by one by using the Fast Forward and Reverse keys on the Roku Remote. The problem is i can only go through about half of the image files before i get an error stating that 'bigbm', the roBitmap being displayed on the screen, is invalid. I think it's because i'm using a GOTO call to change the image file sent to 'bigbm'. I need a fresh set of eyes to point me in the right direction on this. If my method is misguided i would appreciate any suggestions you all might have. I am aware this might be too much code to have you all look through. Giving it a shot anyways because i'm stumped!


' ******
' ****** Scroll a view around a large plane, double buffered
' ******

Library "v30/bslCore.brs"

Function IsHD()
di = CreateObject("roDeviceInfo")
if di.GetDisplayType() = "HDTV" then return true
return false
End Function

sub main()
viewComic("ext1:/Comics/Batman/Batman 001")
end sub

function viewComic(path as string)

'Check if the screen is in HD or not.
if IsHD()
screen=CreateObject("roScreen", true, 1280, 720) 'try this to see zoom
else
screen=CreateObject("roScreen", true)
endif

ImageIndex = 0
imagefiles = matchfiles(path,"*.jpg")


NewFile:
filepath = path + "/" + imagefiles[ImageIndex]
print filepath

'Load comic page with jpg of comic.
bigbm=CreateObject("roBitmap", filepath)
'Check if comic was unable to be created.
if bigbm = invalid
print "bigbm create failed"
stop
endif

'Set background region to that of the image loaded in bigbm.
backgroundRegion=CreateObject("roRegion", bigbm, 0, 0, screen.getwidth(), screen.getheight())
'Check if background region was unable to be loaded.
if backgroundRegion = invalid
print "create region failed"
stop
endif

'Prevent image from overscrolling. Stops at image edges.
backgroundRegion.SetWrap(false)

'Output image to screen.
screen.drawobject(0, 0, backgroundRegion)
screen.SwapBuffers()

msgport = CreateObject("roMessagePort")
screen.SetPort(msgport)

movedelta = 16
if (screen.getwidth() <= 720)
movedelta = 8
endif

codes = bslUniversalControlEventCodes()

pressedState = -1 ' If > 0, is the button currently in pressed state
while true
if pressedState = -1 then
msg=wait(0, msgport) ' wait for a button press
else
msg=wait(1, msgport) ' wait for a button release or move in current pressedState direction
endif
if type(msg)="roUniversalControlEvent" then
keypressed = msg.GetInt()
print "keypressed=";keypressed
if keypressed=codes.BUTTON_UP_PRESSED then
Zip(screen, backgroundRegion, 0,-movedelta) 'up button pressed
pressedState = codes.BUTTON_UP_PRESSED
else if keypressed=codes.BUTTON_DOWN_PRESSED then
Zip(screen, backgroundRegion, 0,+movedelta) ' down button pressed
pressedState = codes.BUTTON_DOWN_PRESSED
else if keypressed=codes.BUTTON_RIGHT_PRESSED then
Zip(screen, backgroundRegion, +movedelta,0) ' right button pressed
pressedState = codes.BUTTON_RIGHT_PRESSED
else if keypressed=codes.BUTTON_LEFT_PRESSED then
Zip(screen, backgroundRegion, -movedelta, 0) ' left button pressed
pressedState = codes.BUTTON_LEFT_PRESSED
else if keypressed = 8 then
print "Rewind"
if ImageIndex = 0 then
'Ignore reverse page request if at end of imagelist.
else
ImageIndex = ImageIndex - 1
GOTO NewFile
end if
else if keypressed = 9 then
print "Fast Forward"
if ImageIndex = ImageFiles.count() then
'Ignore forward page request if at end of imagelist.
else
ImageIndex = ImageIndex + 1
GOTO NewFile
end if
else if keypressed=codes.BUTTON_BACK_PRESSED then
pressedState = -1
exit while
else if keypressed=codes.BUTTON_UP_RELEASED or keypressed=codes.BUTTON_DOWN_RELEASED or keypressed=codes.BUTTON_RIGHT_RELEASED or keypressed=codes.BUTTON_LEFT_RELEASED then
pressedState = -1
end if
else if msg = invalid then
print "eventLoop timeout pressedState = "; pressedState
if pressedState=codes.BUTTON_UP_PRESSED then
Zip(screen, backgroundRegion, 0,-movedelta) 'up button released
else if pressedState=codes.BUTTON_DOWN_PRESSED then
Zip(screen, backgroundRegion, 0,+movedelta) ' down button released
else if pressedState=codes.BUTTON_RIGHT_PRESSED then
Zip(screen, backgroundRegion, +movedelta,0) ' right button released
else if pressedState=codes.BUTTON_LEFT_PRESSED then
Zip(screen, backgroundRegion, -movedelta, 0) ' left button released
end if
end if
end while

end function

function Zip(screen, region, xd, yd)
region.Offset(xd,yd,0,0)
screen.drawobject(0, 0, region)
screen.SwapBuffers()
end function

17 Replies

  • How big are the first five images (the four that works and the one that fails)? Generally there is memory for a "few" screen-sized images, but the number decreases the larger the images get. Since you mentioned they are "mostly" under 2000px (which is pretty huge), I guess your images are pretty big?

    More to the point, is there any reason to have more than one of these bitmaps instantiated at one time? Why are you keeping an array of them?

    --Mark
  • Oh, i was just doing it for testing purposes. I still have the original code that goes through images one by one. I wanted to see if it would still stop working even though there would be no re-allocation going on. Yes, they are pretty big - they hover around the 1900px range.

    First 5 images are 1280x1966, 1280x1966, 1280x1966, 2000x1537, 1280x1966. The one that doesn't work is also 1280x1966. I just tried the channel using 5 random images that are mostly around 700px and none of them worked. Yet the images from the comics have at least the first 4 that are able work with bigger dimensions. Maybe the Roku just isn't meant for this kind of app? 😞 Which is a shame because the images look pretty sweet on my big screen. :mrgreen:
  • Loading that many large images simultaneously is probably maxing-out the available video memory.

    Is there a reason you need more than one screen-sized bitmap in memory at a time? I would maybe load two, and when you load the third, de-allocate the first one.

    - Joel
  • destruk's avatar
    destruk
    Streaming Star
    Another option - I realize you're loading from USB/external - but you could probably get away with copying 100 of those images into the tmp storage area of the roku and then they should swap in and out of ram quicker that way one at a time. If you don't mind the initial copying delay process. Rather than scrolling the images, you could also try chopping each page into individual frames with a left/right control sequence for next and previous frame to reduce the loading and rendering time.
  • Looking at the comments, I had to review your code again. I didn't see at first where in the code you are retaining the bitmaps in memory. Being able to load only 4 or 5 is indicative of retaining the bitmaps in memory. It's also indicative of allocating larger and larger bitmaps with intervening objects that are not deallocated. The first step is to stop retaining both the bitmaps and the regions. Although I can't say exactly what the memory requirements of a region is, I have tested bitmaps. Here's the post where I relate my experience on memory limits and bitmaps.

    If you're allocating large and increasing chunks, I could easily see it taking up memory from fragmentation, see the diagram below.

    Note that in this diagram, bitmap4 is bigger than bitmap3, which is bigger than bitmap2, which is bigger than bitmap1. Any allocation that is not freed (represented by the |x|) causes fragmentation.


    |<---bitmap1--->|x|<-----free ------------------------------------------------------>| AFTER ALLOCATING bitmap1
    |<---free ----->|x|<---bitmap2------->|x|<-----free -------------------------------->| AFTER DEALLOCATING bitmap1 and ALLOCATING bitmap2
    |<---free ----->|x|<---free --------->|x|<---bitmap3--------->|x|<-----free -------->| AFTER DEALLOCATING bitmap2 and ALLOCATING bitmap3
    |<---free ----->|x|<---free --------->|x|<---free ----------->|x|<---bitmap4----------->| FAILS


    Perhaps the allocation of |x| is not obvious. The two examples of fragmenting allocations that are in the code segment you provided are:
    msgport = CreateObject("roMessagePort")
    screen.SetPort(msgport)

    and

    codes = bslUniversalControlEventCodes()

    Move both of these code segments to before the NewFile label. And remove array of regions.

    Then let us know how that works!
  • I'm not sure cropping would work right since it would cut off the text balloons at odd places. I tried saving the images to the tmp: drive but could only get one to be saved there so i scrapped that. I think i'm just bad at programming. Smiley LOL


    Umm...i think my Roku is doing voodoo or something, haha. I rearranged the image file names surrounding, and including, the image file that throws the invalid bitmap error to "z11.jpg, z12-13.jpg, and z14.jpg" instead of the original "11.jpg, 12-13.jpg, and 14.jpg" so that they would appear at the bottom of the list of images in the directory. Somehow the Roku device automatically rearranged them again to the order they are supposed to be in while keeping the zXX.jpg file name. Is that normal for this system, arranging files from right to left maybe?

    Screenshot of what i'm talking about(telnet session):
    http://i.imgur.com/k7ngM.jpg

    Edit: MSGreg, i'll look into that. I didn't see your post until just now. I guess i'll take a breather and just enjoy the Roku for the time being.
  • destruk's avatar
    destruk
    Streaming Star
    I think that would be normal. When you rename a file it remains in the same location in the file allocation table of the device the file resides in. If you are sorting the read filenames in an array, then Z11.jpg is still further down the sorted list than 1.jpg since numbers come first.