Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
BinaryMadman
Visitor

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
0 Kudos
17 REPLIES 17
MSGreg
Visitor

Re: Need help with slightly modified Scroll SDK example

I have found that a Roku 1 is a little more sensitive to memory allocation issues: you have to be careful in what order you allocate and de-allocate large bitmaps. I'm not sure that's what is going on with your code, though.
0 Kudos
renojim
Community Streaming Expert

Re: Need help with slightly modified Scroll SDK example

I have also found that you can only allocate/create so many bitmaps on any model before the call to create a bitmap will fail (return invalid). You probably need to do some kind of garbage collection and/or destroy your roScreen and create a new one.

Good luck!
-JT
Roku Community Streaming Expert

Help others find this answer and click "Accept as Solution."
If you appreciate my answer, maybe give me a Kudo.

I am not a Roku employee.
0 Kudos
TheEndless
Channel Surfer

Re: Need help with slightly modified Scroll SDK example

I believe the key is invalidating the bitmap and the region before creating the new one. In your code, you're creating a new bitmap without invalidating the previous one, so the memory from the previous bitmap is still going to be in use when you try creating the new one. You should also invalidate the region before creating the new bitmap, because it will hold the reference to the previous bitmap open, resulting in the same issue.

Add the following lines immediately after your "NewFile:" label and see if it helps:
bigbm = invalid
backgroundRegion = invalid
My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
0 Kudos
BinaryMadman
Visitor

Re: Need help with slightly modified Scroll SDK example

"TheEndless" wrote:
I believe the key is invalidating the bitmap and the region before creating the new one. In your code, you're creating a new bitmap without invalidating the previous one, so the memory from the previous bitmap is still going to be in use when you try creating the new one. You should also invalidate the region before creating the new bitmap, because it will hold the reference to the previous bitmap open, resulting in the same issue.

Add the following lines immediately after your "NewFile:" label and see if it helps:
bigbm = invalid
backgroundRegion = invalid

I added those two lines of code and unfortunately it still has the same problems. Debug screen either says the bigbm create failed or or backroundRegion failed.

You probably need to do some kind of garbage collection and/or destroy your roScreen and create a new one.

What kind of statements do i need to use to do some garbage collection, just set the object to invalid? I tried something called RunGarbageCollector() but that didn't help. I'm sure there has got to be a way to do this, roSlideshow is able to go through 25+ image pages without memory error. It would have been even better if roSlideShow supported scrolling, i wouldn't need to create my own. 😄
0 Kudos
renojim
Community Streaming Expert

Re: Need help with slightly modified Scroll SDK example

The last time I had problems with running out of memory, I did a few experiments. It seemed that simply setting a variable to invalid didn't accomplish anything. Running the garbage collector also didn't help much. This was based on printing out the results of RunGarbageCollector(). What did seem to help was to let my roScreen go out of scope completely. Running the garbage collector after that also may have helped, but I don't remember if I tried it both ways.

What I ended up with was creating an underlying roImageCanvas in my main routine and then calling a function that created an roScreen and everything else. After I had created numerous bitmaps and at an opportune time, I'd return back to my main routine, thus allowing the roScreen to close and go out of scope, and then run the garbage collector. Then I'd call the function that created the roScreen again and recreate everything. It' not perfect. If you run my app long enough it will still run out memory. Based on the output of RunGarbageCollector() there are still things that are not getting deallocated, but I felt it was good enough and I didn't bother to try to figure out why things I wasn't using anymore weren't getting cleaned up.

I'm not saying that the roScreen is the problem since obviously anything created in the routine that created the roScreen also goes out scope when the routine returns back to main. I'm using many bitmaps and regions.

Obviously, I don't fully understand what's going on with object allocation/deallocation. That's kind of why I said, "Good luck!". If you figure out anything I'd love to hear about it.

-JT
Roku Community Streaming Expert

Help others find this answer and click "Accept as Solution."
If you appreciate my answer, maybe give me a Kudo.

I am not a Roku employee.
0 Kudos
TheEndless
Channel Surfer

Re: Need help with slightly modified Scroll SDK example

JT, for what it's worth, my aquarium screensaver never lets the roScreen go out of scope, and it fully refreshes itself (loads all new bitmaps, 30+) every 15 minutes without issue. It does, however, ensure that all other bitmaps and regions go completely out of scope before re-loading, which is why I suggested that might be the issue. It also uses the roCompositor for most of them, so it could be that it has better memory management built into it.
My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
0 Kudos
MSGreg
Visitor

Re: Need help with slightly modified Scroll SDK example

TL;DR Try allocating the msg port right after allocating the roScreen and outside the loop.

This may help in keeping memory from being fragmented.

Here is the reference guide on Garbage Collection. Objects are de-allocated when they are assigned invalid; more precisely: when their reference count goes to zero. RunGarbageCollection() is only necessary to remove circular references. I also thought about setting to invalid (as TheEndless suggested) but wasn't sure in the original statement if the de-allocation occurred before the allocation or vice versa. Setting to invalid certainly removes the ambiguity.

In my experience, the order of allocations / de-allocations make a difference. I presume because of memory fragmentation. Take care to de-allocate everything you've allocated since the bitmap. In the code, you are allocating a msgport after the bitmap. And it's being allocated/de-allocated every loop.
0 Kudos
BinaryMadman
Visitor

Re: Need help with slightly modified Scroll SDK example

I've tried de-allocating just about everything that can be de-allocated. I just tried to make it more simple by using an array of roRegions and it looks like it can only do 4 items before saying the bitmap 'bmImage' was unable to be created. I find that to be a bit odd that it would stop working that early into it.

UPDATED CODE:

' ******
' ****** 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/Wonder Woman/Wonder Woman 002")
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


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

print imagefiles.count()
backgroundRegion = [imagefiles.count()]

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

for i = 0 to imagefiles.count() - 1
print imagefiles[i]
bmImage = invalid
bmImage = CreateObject("roBitmap", path + "/" + imagefiles[i])
if bmImage = invalid then
print "bmImage is invalid"
end if
backgroundRegion[i]=CreateObject("roRegion", bmImage, 0, 0, screen.getwidth(), screen.getheight())
if backgroundRegion[i] = invalid then
print "create region failed"
end if
end for

NewFile:

'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.


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

'Output image to screen.
screen.drawobject(0, 0, backgroundRegion[ImageIndex])
screen.SwapBuffers()
screen.finish()

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 forward 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
print "ERROR: msg is Invalid"
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

0 Kudos
destruk
Binge Watcher

Re: Need help with slightly modified Scroll SDK example

I'm not sure if this would be applicable, but there was a post stating that the maximum size image that can be loaded was reduced to 2048x2048 - perhaps one of your images is larger than that?
What happens if you shuffle or randomize the images - does it always fail for you on the same number in the queue? What do the failing images have in common?
0 Kudos