Hi I am new to Roku development using brightscript. Please excuse me if im asking something stupid.
I am stuck in loading some images I got through roUrlTransfer object. This is what I am doing:
Create seperate roUrlTransfer objects for each images (since I need it async) - call it ‘http’
Saving the resul to tmp using AsyncGetToFile(temp_path)
Pushing each http to imageTransfers array
Finally, take each item from imageTransfers array and drawing bitmap out of it
I have a grid control which has 4 rows and 2 col (so initially 8 images will load). After that on each button_down_pressed event, i’m loading next row (2 items). But when I do
for each http in m.imageTransfers
msg = wait(0, http.GetPort())
if (type(msg) = “roUrlEvent”)
…
…
end if
end for
the code stops working at msg=wait(0, http.GetPort()). Its like an infinite wait. What am I doing wrong here? The initial 8 items in the grid is loading fine, and passing this code successfully. Please help :roll:
For what you want to do you are probably better
Off using rotexturemanager And do not use wait
But create a separate port for just your textures
and use port.getmessage In any case your async
Objects must stay on scope until it completes
I use it with the 2xd. Essentially does the same thing
As urltransfer. But it also returns an in memory bitmap
Reference to you. The transfer object writes to disk so
You have to load your bitmap from tmp. If I preload something
For use later on I use the transfer object. For loading directly
Into a grid I prefer the texturemanager. Performance wise they area out the same
With retrieving. Did notice along with someone else recently that
The transfer object my give slightly better download times on a single larger
Bitmap than the texturemanager. But for more than one on a component
Such as a grid during realtime scrolling definitely the manager
With the 2xd box i have to balance size, and number with performance
The textures arrive quick enough. But are disk and processor
Intensive. To see what I mean just start scrolling your home screens
Ok the 2 boxes. You will notice resistance and uneven movement
As the textures arrive during scrolling. If you open up a telnet
You can see that the manager or some equivalent is being used.
In the 4200 boxes it just absolutely impressive. No studdering at all
I tried roTextureManager. I have to load 20-25 or so images initially. It starts well, but after a while, most of the roTextureRequestEvent states are returining 4, which means Failed.
Is this a limitation of the texturemanager? Is there any work around?
20 -25 is well within reason for standard
Grid size textures. A failure code can mean
That your roTextureRequest may have gone
Out of scope. If you are requesting textures
asynchronously and not polling for returns
Within the same function , you need to
Make sure your texture requests are global to
Either an object or your application
If they go out of scope such as when creating them
Locally In a function and then exiting the
Function to listen somewhere else, they
Are removed from the function stack that
Created them and
Destroyed. This would generate a return of
4. Without seeing your code it is difficult
To determine where your problem is
I am calling a function called sendRequest, which creates a roTextureReques object with the passed in url and send a RequestTexture request. As return, I am passing request object
The request object is pushed to an imageTransfers array
So, now I have imageTransfers array with all the roTextureRequest objects.
then i loop through each items in the imagetransfers and calling a listening function. (here im using the same message port created at the time of request) and wait for the roTextureRequestEvent
for first 12 items state =3, after that state=4.
The first 12 items remains in the scope. and I cant find any reason for the remaining items go out of the scope.
Create,push, send, receive, pop, destroy
Totally Recreate again when needed
Do not reuse a completed object
To re-request if removed from the manager
As a matter of fact it is better to save the
Bitmap than to save the request
Push onto an associative array list
With the objects. Id so you can find it
And pop it off the queue when returned
' This is an example of one way to manage a texture cache. It is a very stripped down version
' of one that I use. This version does not include the realtime populating of my grids that I have
' put out here. I do have that if anyone is interested. This version just includes the polling function
' that is used primarily for pseudo-async preloading. But it demonstrates what is essentially needed to
' do this as well as an indicator of how fast the manager can be. I have set up a test directory on my
' own content site. The image files are small but I have acceptable results with images as large
' as 10 - 18 kb. So for standard grid-sized poster images this should be very reasonable
' This was extracted from my channel and put together very quickly, and most of the error checking was removed.
' But I believe I have included enough code to demonstrate a particular method that I use. However some anomalies
' may exist, which if discovered I will be happy to fix
' My own experience with the manager is only about 4 months but I have learned a lot and have come to really appreciate
' the texture manager. It works very well with my grids which I have redesigned to be fully integrated with
' my managers. If anyone can contribute and make it better we can all benefit
' Add this function to test the code
Function TextureTest() As Void
' This directory is temporary and will be available for testing
l_url = "http://s3.amazonaws.com/NMLiving/texture_test/"
' I have created 25 simple textures texture1.jpg to texture25.jpg
l_textureList = CreateObject( "roArray", 25, False )
' Create the url, the textureobject and push onto the texture list
for l_i = 1 to 25
l_turl = l_url + "texture" + l_i.ToStr() + ".jpg"
l_textureList.Push( NewTextureObject( l_turl ) )
end for
' Create an instance of the texturemanager and reset (optional)
' However you should know when to reset
l_textureManager = NewTextureManager()
l_textureManager.Reset()
print "REQUESTING"
print "============================================================="
' For each texture in the list request it from the manager
for each l_texture in l_textureList
l_textureManager.RequestTexture( l_texture )
end for
print ""
print "RECEIVING"
print "============================================================"
' Ask the manager to poll for the textures
l_textureManager.PollTextures()
' Verify that we have a valid bitmap for each texture
for each l_texture in l_textureList
print type( l_texture.Bitmap )
end for
End Function
' Creates a texture cache object which contains the returned bitmap, the textureRequest
' a Url and a resend count
Function NewTextureObject( a_url As String ) As Object
return { Bitmap: Invalid, TRequest: Invalid, TUrl: a_url, ResendCount: 0 }
End Function
' Very stripped down version of my own manager. This version offers only polling
' you would not use polling to populate a grid during realtime scrolling on for preloading
Function NewTextureManager() As Object
tl = CreateObject( "roAssociativeArray" )
tl.TManager = CreateObject( "roTextureManager" )
tl.TMPort = CreateObject( "roMessagePort" )
tl.TManager.SetMessagePort( tl.TMPort )
tl.RequestList = CreateObject( "roAssociativeArray" )
tl.SendCount = 0
tl.ReceiveCount = 0
tl.STATE_READY = 3
tl.STATE_FAILED = 4
tl.AddItem = tl_add_item
tl.RemoveItem = tl_remove_item
tl.Reset = tl_reset
tl.RequestTexture = tl_request_texture
tl.ReceiveTexture = tl_receive_texture
tl.PollTextures = tl_poll_textures
return tl
End Function
' Adds an item to the list and increments the list count. The key is the textures id
Function tl_add_item( a_ID As Integer, a_value As DYNAMIC ) As Void
m.RequestList.AddReplace( a_ID.ToStr(), a_value )
m.ListCount = m.ListCount + 1
End Function
' Removes an item from the list, decrements the count
Function tl_remove_item( a_ID As Integer ) As Object
l_key = a_ID.ToStr()
l_value = m.RequestList.LookUp( l_key )
if l_value = Invalid then return Invalid
m.RequestList.Delete( l_key )
m.ListCount = m.ListCount - 1
return l_value
End Function
' Resets the list by emptying the manager and clearing
' out any items remaing, resets all values
Function tl_reset() As Void
m.TManager.CleanUp()
m.RequestList.Clear()
m.ListCount = 0
m.SendCount = 0
m.ReceiveCount = 0
End Function
' Each texture object is sent to this function, which creates the texturerequest and sends it
' It also increments the sendcount
Function tl_request_texture( a_texture As Object ) As Integer
' Create the texture request and assign to the items TRequest member
a_texture.TRequest = CreateObject( "roTextureRequest", a_texture.TUrl )
' Add the item into the async list
m.AddItem( a_texture.TRequest.GetID(), a_texture )
' Asynchronously request the texture
m.TManager.RequestTexture( a_texture.TRequest )
' Increment the send count
m.SendCount = m.SendCount + 1
' Return the current total sent
print m.SendCount" "; a_texture.TUrl
return m.SendCount
End Function
' This function receives the texture and processes it, if successful it increments the receive count
Function tl_receive_texture( a_tmsg as DYNAMIC ) As Boolean
' Get the returned state
l_state = a_tmsg.GetState()
' If return state is Ready, Failed, or Cancelled - either case, remove it from the list
if l_state = m.STATE_READY or l_state >= m.STATE_FAILED
' Removed the received texture from the asynclist. But do not increment the received count
l_texture = m.RemoveItem( a_tmsg.GetID() )
' There SHOULD ALWAYS be one in there if used properly
if l_texture = Invalid then return False
' Assign the bitmap to the texture object
l_texture.Bitmap = a_tmsg.GetBitmap()
' A state of 3 with a valid bitmap is complete
if l_state = m.STATE_READY and l_texture.Bitmap <> Invalid
' Increment the receive count and get rid of the texture request
m.ReceiveCount = m.ReceiveCount + 1
l_texture.TRequest = Invalid
print m.ReceiveCount;" "; l_texture.TUrl
return True
' If a failure occurs you can try to resend it, but usually it is a more serious problem which
' can put you in an endless loop if you dont put a limit on it. I handle it differently but for this
' example it is resent a limited number of times
else if l_state = m.STATE_FAILED and l_texture.ResendCount <= 5
' Optional
l_texture.TRequest = Invalid
' Rebuild and resend
l_texture.ResendCount = l_texture.ResendCount + 1
l_texture.TRequest = CreateObject( "roTextureRequest", l_texture.TUrl )
m.AddItem( l_texture.TRequest.GetID(), l_texture )
m.TManager.RequestTexture( l_texture.TRequest )
' Set the global error
l_str = "Resend Texture Request. State : " + l_state.ToStr()
l_str = l_str + " Bitmap: " + type( a_tmsg.GetBitmap() ) + " ResendCount: " + l_texture.ResendCount.ToStr()
l_str = l_str + " URI: " + l_texture.TUrl
print l_str
return False
' This can occur with the dylnamic allocation when the textures are not removed from the queue fast enough
' or the resend count has expired, cancelled etc...
else
l_str = "Unhandled Message. State: " + l_state.ToStr() + " Bitmap: " + type( a_tmsg.GetBitmap() )
l_str = l_str + " URI: " + l_texture.TUrl
print l_str
return False
end if
end if
' Otherwise it is some other code such as downloading if it even exists. Never seen it
return True
End Function
' This function simply polls for all the textures to return. To populate a grid during realtime scrolling
' a little modification is needed to the grids I have put out here and this manager I have this available
' in my own library
Function tl_poll_textures() As Boolean
' Just a timeout here you may want to add something like I do to allow the user to abort under
' certain conditions. That was removed for simplicity
l_timer = CreateObject( "roTimeSpan" )
l_timeOut = 45
l_kp_BK = 0
l_success = False
while( True )
' Monitor the managers port
l_TMsg = m.TMPort.GetMessage()
if l_TMsg <> Invalid
' Process the received texture
m.ReceiveTexture( l_TMsg )
' When receivecount is = to send count then we have them all
' you have to be careful here any abnormality or failure in the chain can effect this
' I do it differently with more error checking but this is only a demonstration
l_success = ( m.ReceiveCount = m.SendCount )
if l_success then exit while
' Reset the timer
l_timer.Mark()
end if
' Should always have a timeout as anything can occur
if ( l_timer.TotalSeconds() >= l_timeout )
print "TextureRequest Timed Out"
exit while
end if
end while
return l_success
End Function
Thank you NewManLiving for sharing the code. This code is great, I tried it with my app and the same issue happens.
But I got some insight of what is going on. My images are huge, even though they are grid thumbnails and each of it is around 90kb in size (1050 X 590). It starts failing exactly after 16 successful requests.
I tried the same code with smaller images of 43kb (460 X 360) and it passed! All requests passed successfully.
So I think my assets are going over limit (in terms of dimension - width and height of images) what texture Manager can handle. Any thoughts?
Open up a telnet session at the box ip and port
Issue the command r2d2_bitmaps. The first time
The command will fail. The second + times will
Allow you to see how much memory your
Images are using.
Yes it does. And if you plan on supporting
The 2 boxes then you have even less, a little more than
Half the memory if the 3 box. 38 or 39 depending
On the firmware. You did indeed run out of memory
Read the documentation on roBitmap for some
Further insight
One other thing you should be aware that a 200 * 200 bitmap is just that in memory, regardless of the type and size of the file. For example a png might be larger
than a jpg but since they are both 200 * 200 they occupy the same amount of memory. The smaller file size is important only for downloading. As far as ROKU memory is concerned there is no difference. You can use roURLTransfer to write your images to disk and open and discard as the user moves along. You can also do this with
the texturemanager by creating what I call a cache cloud. It appears to have some sort of LRU so the next loading is faster. You just load and unload as you go along
However, in my opinion, Program design within the modest limitations of ROKU memory constraints is the primary issue. Would be nice if it had the same memory as
Apple TV or even the new Fire TV. Been dabbling with that as well. Got my eclipse set up for both environments. But Fire TV has its pitfalls as well. Android based
girds are clunky. Bloated Java Code with a ton of packages just to say 'Hello World". Really like the ROKU the best for development. Just does not have it in the memory department
I have a series of screens with grid populated through texturemanager. When I load the main (home) page: Available memory 26452096 used 23547904 max 50000000
Once I go from the main page, there is another page with grid generated similarly.
At this point of time; r2d2_bitmaps says: Available memory 6111360 used 43888640 max 50000000
and is understanable.
But once I navigate back to the main page, i am disposing all the bitmaps to free up the memory.
function dispose() as
m.manager.CleanUp()
m.requestList.Clear()
m.ListCount = 0
m.sendCount = 0
m.receiveCount = 0
end function
but still r2d2_bitmaps says: Available memory 6111360 used 43888640 max 50000000
Which actually means that, bitmaps remain in the memory. and eventually app goes out of memory and crahses.
How to deal with this?
All bitmap variables that were assigned to any list
Must be set to invalid. All held texture requests
Must be set to invalid
Not home right now but the idea is
For each texture in texturelist
Texture.bitmap = invalid
Texture.TRequest = invalid
End for
All and every held reference must be set
To invalid like any other object before memory
Is released
If you look at your telnet list
You can see the bitmaps that are still
In memory. They are the same size as
Your images with 3 extra bytes. May be 4
Don’t really look at those extra bytes much
When you don’t see them in the
List anymore then they
Are all released. There is one exception
Which occurs when bitmaps are released
And swapbuffers or finish is not called
Then you may notice hanging bitmaps
People on here worked without r2d2_bitmaps
For years. I would have packed it away
If I had to keep guessing or constantly
Measuring.
“sonnykr” wrote:
Ok, I think you can help me in this issue: I have a series of screens with grid populated through texturemanager. When I load the main (home) page: Available memory 26452096 used 23547904 max 50000000
Once I go from the main page, there is another page with grid generated similarly. At this point of time; r2d2_bitmaps says: Available memory 6111360 used 43888640 max 50000000
and is understanable.
But once I navigate back to the main page, i am disposing all the bitmaps to free up the memory. … but still r2d2_bitmaps says: Available memory 6111360 used 43888640 max 50000000
…eventually app goes out of memory and crahses. How to deal with this?
I saw you opened new topic but answering here, since there you don’t mention using roGridScreen; here you do and i think it might be important. Are you getting rid of the roGridScreen before returning to main menu or is it lingering still in some variable/global?
I seem to remember roGridScreen is a very special beast with special treatment for video memory and “damaging” some underlying screens (or was it the other way around. don’t think was documented but can be found on the forum). My impression is it is a greedy beast and having >1 grid screen in existence is looking for trouble.