Need to Modify SDK Videoplayer to Allow Display of Image

I’m guessing that this is a unique need here, and I’m wondering if this is even possible. I’m building a video channel using “Videoplayer” from the SDK as my template guide. I’ve figured out how to set it up to play videos using my own custom XML files. That was the easy part. Here’s what I’m stuck on: is it possible to modify the channel code, or the XML code or both to allow for ONE of my Categories to fetch and display a remote static .gif image instead of a remote mp4 video?
Here’s a little more insight into what I’m trying to create here: the channel is weather-related. It will primarily host videos of weather events (again, this part is complete…XML files that point to the videos - no problem), but I want one Category to point to static .gif images which consist of forecast maps published by the National Weather Service. The URL for These .gifs never change. So a static link to these .gifs will always yield the latest forecast map. It’s this last Category feature that I’m racking my brain on. How do I make this Category display these images when the code is looking for an mp4 video file to play? If it’s any help: these .gifs display perfectly within the small sd and hd Poster frame, and they do show the latest .gif within that small frame. Now if only I could figure out how to expand it to full screen so the viewer can see it better.
Any help is greatly appreciated.

Take a look at the function showDetailScreen in the file appDetailScreen.brs

find this spot:


           if msg.GetIndex() = 1
                    PlayStart = RegRead(showList[showIndex].ContentId)
                    if PlayStart <> invalid then
                        showList[showIndex].PlayStart = PlayStart.ToInt()
                    endif
                    showVideoScreen(showList[showIndex])
                    refreshShowDetail(screen,showList,showIndex)
                endif
                if msg.GetIndex() = 2
                    showList[showIndex].PlayStart = 0
                    showVideoScreen(showList[showIndex])
                    refreshShowDetail(screen,showList,showIndex)

what you would want to do is add some logic to check for an image and then write an image display function that would display the image, otherwise, play a video.

For example, in your xml, you could set image and or .gif

Then in the above function you could have:

               if msg.GetIndex() = 2
                    showList[showIndex].PlayStart = 0

               if Showlist[ShowIndex].streamformat=".gif" or Showlist[Showindex].StreamFormat="image" then
                    showImage(showlist[showindex])
               else
                    showVideoScreen(showList[showIndex])
               end if

               refreshShowDetail(screen,showList,showIndex)
  • Joel

Joel:
As always, thank you for replying and for your help.

I believe I did what you recommended, but I’m still not able to open the image to full screen. When I press “Play,” the screen goes black and the “retrieving” bar starts to load for about a half second. Then it quits and returns back to where I just was.

Here is the section of code from the apsDetailScreen.brs which I believe I modified exactly as you suggested. I’m pasting the entire section just for reference:

PORTION OF apsDetailScreen.brs CODE:


'***************************************************************
'** The show detail screen (springboard) is where the user sees
'** the details for a show and is allowed to select a show to
'** begin playback.  This is the main event loop for that screen
'** and where we spend our time waiting until the user presses a
'** button and then we decide how best to handle the event.
'***************************************************************
Function showDetailScreen(screen As Object, showList As Object, showIndex as Integer) As Integer

    if validateParam(screen, "roSpringboardScreen", "showDetailScreen") = false return -1
    if validateParam(showList, "roArray", "showDetailScreen") = false return -1

    refreshShowDetail(screen, showList, showIndex)

    'remote key id's for left/right navigation
    remoteKeyLeft  = 4
    remoteKeyRight = 5
 
    while true
        msg = wait(0, screen.GetMessagePort())

        if type(msg) = "roSpringboardScreenEvent" then
            if msg.isScreenClosed()
                print "Screen closed"
                exit while
            else if msg.isRemoteKeyPressed() 
                print "Remote key pressed"
                if msg.GetIndex() = remoteKeyLeft then
                        showIndex = getPrevShow(showList, showIndex)
                        if showIndex <> -1
                            refreshShowDetail(screen, showList, showIndex)
                        end if
                else if msg.GetIndex() = remoteKeyRight
                    showIndex = getNextShow(showList, showIndex)
                        if showIndex <> -1
                           refreshShowDetail(screen, showList, showIndex)
                        end if
                endif
            else if msg.isButtonPressed() 
                print "ButtonPressed"
                print "ButtonPressed"
                if msg.GetIndex() = 1
                    PlayStart = RegRead(showList[showIndex].ContentId)
                    if PlayStart <> invalid then
                        showList[showIndex].PlayStart = PlayStart.ToInt()
                    endif
                    showVideoScreen(showList[showIndex])
                    refreshShowDetail(screen,showList,showIndex)
                endif
                if msg.GetIndex() = 2
                    showList[showIndex].PlayStart = 0
					if Showlist[ShowIndex].streamformat=".gif" or Showlist[Showindex].StreamFormat="image" then
                    showImage(showlist[showindex])
               else
                    showVideoScreen(showList[showIndex])
               end if
                    refreshShowDetail(screen,showList,showIndex)
                endif
                if msg.GetIndex() = 3
                endif
                print "Button pressed: "; msg.GetIndex(); " " msg.GetData()
            end if
        else
            print "Unexpected message class: "; type(msg)
        end if
    end while

    return showIndex

End Function

Now, here is the entire xml file through which I’m trying to display this remote gif. It is formatted the exact way all of the others which link to mp4 video feeds are formatted. Per your instructions, I changed the tag to image and the tag to .gif

If you can see what I’m doing wrong from what I’ve provided here, please let me know.

Many thanks, Joel!

XML CODE:


<feed>

<!-- resultLength indicates the total number of results for this feed --><resultLength>1</resultLength><!-- endIndix  indicates the number of results for this *paged* section of the feed --><endIndex>1</endIndex>

<item sdImg="http://www.spc.noaa.gov/products/outlook/day1probotlk_1200_torn.gif" hdImg="http://www.spc.noaa.gov/products/outlook/day1probotlk_1200_torn.gif">
<title>24 Hour Tornado Outlook</title>

<contentType>image</contentType>
<contentQuality>SD</contentQuality>

<media>
<streamFormat>.gif</streamFormat>
<streamQuality>SD</streamQuality>
<streamBitrate>1500</streamBitrate>
<streamUrl>http://www.spc.noaa.gov/products/outlook/day1probotlk_1200_torn.gif</streamUrl>
</media>

<synopsis>The 24 Hour Tornado Outlook from the National Weather Service.</synopsis>

<genres>Weather</genres><runtime>100</runtime></item>

</feed>

If you’re seeing the “retrieving” screen, then you must be calling showVideoScreen rather than showImage. The image display functions don’t display a retrieving message. Either that, or your showImage function is invoking the video screen. I would add some print statements to trace the flow of execution and the variables of interest.

–Mark

Two things:

if Showlist[ShowIndex].streamformat=".gif" or Showlist[Showindex].StreamFormat="image" then

should be

if Showlist[ShowIndex].streamformat=".gif" or Showlist[Showindex].contentType="image" then

My bad.

Second, the tag in your xml is inside the media tag, for the syntax above to work, you would need to have a streamformat tag and some code to parse it outside the media tag. I suggest you just use the ContentType tag

if Showlist[Showindex].contentType="image" then

You will also need to handle the same in the case where button 1 is pressed

  • Joel

@ Mark:

Thank you for your input. However, I wish I was able to figure out how to implement your suggestion. Sadly, my experience with this type of code is very limited so far, but I’m happy that I am learning a lot as I push through these challenges.

@ Joel:

I thought I tried to implement the few changes you suggested. Unfortunately, I’m still getting the same results I reported last night.

Here’s the section of code as it stands now:


'***************************************************************
'** The show detail screen (springboard) is where the user sees
'** the details for a show and is allowed to select a show to
'** begin playback.  This is the main event loop for that screen
'** and where we spend our time waiting until the user presses a
'** button and then we decide how best to handle the event.
'***************************************************************
Function showDetailScreen(screen As Object, showList As Object, showIndex as Integer) As Integer

    if validateParam(screen, "roSpringboardScreen", "showDetailScreen") = false return -1
    if validateParam(showList, "roArray", "showDetailScreen") = false return -1

    refreshShowDetail(screen, showList, showIndex)

    'remote key id's for left/right navigation
    remoteKeyLeft  = 4
    remoteKeyRight = 5
 
    while true
        msg = wait(0, screen.GetMessagePort())

        if type(msg) = "roSpringboardScreenEvent" then
            if msg.isScreenClosed()
                print "Screen closed"
                exit while
            else if msg.isRemoteKeyPressed() 
                print "Remote key pressed"
                if msg.GetIndex() = remoteKeyLeft then
                        showIndex = getPrevShow(showList, showIndex)
                        if showIndex <> -1
                            refreshShowDetail(screen, showList, showIndex)
                        end if
                else if msg.GetIndex() = remoteKeyRight
                    showIndex = getNextShow(showList, showIndex)
                        if showIndex <> -1
                           refreshShowDetail(screen, showList, showIndex)
                        end if
                endif
            else if msg.isButtonPressed() 
                print "ButtonPressed"
                print "ButtonPressed"
                if msg.GetIndex() = 1
                    PlayStart = RegRead(showList[showIndex].ContentId)
                    if PlayStart <> invalid then
                        showList[showIndex].PlayStart = PlayStart.ToInt()
                    endif
                    if Showlist[showIndex].contentType="image" then
                    showImage(showList[showIndex])
               else
                    showVideoScreen(showList[showIndex])
               end if
                    refreshShowDetail(screen,showList,showIndex)
                endif
                if msg.GetIndex() = 2
                    showList[showIndex].PlayStart = 0
					if showList[showIndex].contentType="image" then
                    showImage(showList[showIndex])
               else
                    showVideoScreen(showList[showIndex])
               end if
                    refreshShowDetail(screen,showList,showIndex)
                endif
                if msg.GetIndex() = 3
                endif
                print "Button pressed: "; msg.GetIndex(); " " msg.GetData()
            end if
        else
            print "Unexpected message class: "; type(msg)
        end if
    end while

    return showIndex

End Function

And here is the XML file:


<feed>

<!-- resultLength indicates the total number of results for this feed --><resultLength>1</resultLength><!-- endIndix  indicates the number of results for this *paged* section of the feed --><endIndex>1</endIndex>

<item sdImg="http://www.spc.noaa.gov/products/outlook/day1probotlk_1200_torn.gif" hdImg="http://www.spc.noaa.gov/products/outlook/day1probotlk_1200_torn.gif">
<title>24 Hour Tornado Outlook</title>

<contentType>image</contentType>
<contentQuality>SD</contentQuality>

<media>

<streamQuality>SD</streamQuality>
<streamBitrate>1500</streamBitrate>
<streamUrl>http://www.spc.noaa.gov/products/outlook/day1probotlk_1200_torn.gif</streamUrl>
</media>

<synopsis>The 24 Hour Tornado Outlook from the National Weather Service.</synopsis>

<genres>Weather</genres><runtime>100</runtime></item>

</feed>

As you suggested, I took out and just left .

Then, I shortened:

if Showlist[ShowIndex].streamformat=".gif" or Showlist[Showindex].contentType="image" then

To this:

if Showlist[Showindex].contentType="image" then

But, still, it’s just not opening the image. It still does the “retrieve” for a split second and then back.

Any help is greatly appreciated. And, if this type of function is just not meant to coexist within a video app, then that’s fine too. This channel will be video driven. This is just an extra “perk” that I’d like to have in there.
Thanks again for any advice that could assist me in accomplishing this.

In appDetailScreen.brs, the line:

if Showlist[showIndex].contentType="image" then

will never evaluate to true (i.e. you will never see that contentType equals “image”), because of a bug in showFeed.brs. The problem is that the contentType is read from the xml file, then subsequently set to “episode”, overwriting the value read from the xml file.

The solution is to move the following lines in showFeed.brs to immediately after the line that says: item = init_show_feed_item()


'Set Default screen values for items not in feed
item.HDBranded = false
item.IsHD = false
item.StarRating = "90"
item.ContentType = "episode" 

And, if you haven’t already done so, you’ll have to write a ‘showImage’ function, e.g:


Function showImage (image As Object)
	ss = CreateObject ("roSlideShow")
	port = CreateObject ("roMessagePort")
	ss.SetMessagePort (port)
	ss.AddContent ({Url: image.SDPosterUrl})
	ss.SetUnderscan (3)
	ss.Show ()
	While True
		msg = Wait (0, port)
		If Type (msg) = "roSlideShowEvent"
			If msg.IsScreenClosed ()
				ss.Close ()
				Exit While
			EndIf
		EndIf
	End While
End Function

Thank you very much, belltown!!!
I followed everything you said to do, and I am now able to press “Play” and it now does open the image!

Unfortunately, there is a bit of a “glitch” happening. The problem only happens when I try to open an image that is a .gif. What it does is it takes the upper left corner of the gif and places it at the center of the screen. The result is that image then extends down and to the right of this center spot and then a vast amount of the image ends up going off screen. After playing with ss.setunderscan and anything else I could think of in the code, I decided to try a different image at a different URL. As luck would have it, the first image I tried happened to be a jpeg, and it displayed perfectly on the screen. After a few trials, I was able to narrow this issue down to the image being a gif as being the cause.

I took a couple of photos of my TV just to illustrate this:

This is the photo of the TV screen with the channel under construction displaying an image as a jpeg
https://www.dropbox.com/s/3b3xspsldyxfcjs/jpeg.jpg

And this is what a gif does. (It’s dark and hard to see the outline of the TV, but use the blue dot as a reference and note that both photos are from the same position and both images are the same size)
http://www.dropbox.com/s/gnq7u1lpnobl53s/gif.jpg

I’ve searched this forum and online for possible solutions, and I’m coming up blank.

Unfortunately, in this case, I’m at the mercy of the National Weather Service in that I can’t just tell the channel to show an jpeg. Since the particular map I want to display is published by the NWS in gif format only, I need this to work with the gif format.

I’m not sure if I need to put something within the XML code to tell the gif to center.

belltown, Joel and Mark, I really appreciate all of your help on getting me this far. If there’s a way I can fix this small issue, then I’ll basically be ready to finish the coding portion of this channel and then focus on getting the video content ready.
Thank you all again!

can you dropbox me (via private message) a copy of the channel you are developing so we can investigate? Sounds to me like it could be a bug, and I would like to verify it.

Meanwhile, you should be able to tell the filetype using instr() and perhaps adjust the x/y coordinates to handle the odd display issue. If you are going to send us the project however, please send it before you try to fix the problem!

  • Joel

It may be a bug in the way roSlideShow handles gif images, although on my Roku 2 (4.9/5060) it displays correctly.

You could try using an roImageCanvas instead of an roSlideShow. Try this showImage function instead:


Function showImage (image As Object)

	' Get the TV's display size
	di = CreateObject ("roDeviceInfo")
	displaySize = di.GetDisplaySize ()
	displayMode = di.GetDisplayMode ()
	
	' Make use of the 'Action Safe Zone'
	'	HD->1150x646 starting at (64, 35)
	'	SD->648x432, starting at (36, 24)
	If displayMode = "720p"			' 720p (HD)
		displayH% = 646
		displayW% = 1150
		displayX% = 64
		displayY% = 35
	Else If displayMode = "480i"	' 480p (SD)	
		displayH% = 432
		displayW% = 648
		displayX% = 36
		displayY% = 24
	Else							' Unknown display type
		displayH% = displaySize.H * 0.9
		displayW% = displaySize.W * 0.9
		displayX% = (displaySize.W - displayW%) / 2
		displayY% = (displaySize.H - displayH%) / 2
	EndIf

	port = CreateObject ("roMessagePort")
	ic = CreateObject ("roImageCanvas")
	ic.SetMessagePort (port)

	' Black opaque background
	ic.SetLayer (0, {Color: "#FF000000", CompositionMode: "Source"})
	
	' Fill the display area with the image
	' Display the title just below the top center of the image
	ic.SetLayer (1, [{url: image.SDPosterUrl,
						TargetRect: {x: displayX%, y: displayY%, w: displayW%, h: displayH%}},
					{Text: image.Title,
						TextAttrs: {Color: "#AA777777", Font: "Medium", HAlign: "Center", VAlign: "Top"},
						TargetRect: {x: displayX%, y: displayY% + 10, w: displayW%, h: displayH% - 10}
					}])
	ic.Show ()

	While True
		msg = Wait (0, port)
		If Type (msg) = "roImageCanvasEvent"
			If msg.IsScreenClosed ()
				ic.Close ()
				Exit While
			Else If msg.IsRemoteKeyPressed ()
				key = msg.GetIndex ()
				' Exit regardless of which key is pressed
				ic.Close ()
				Exit While
			EndIf
		EndIf
	End While
End Function