Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 

Captions Problem!

I am working on an application that uses a custom screen to display videos with subtitles. I am using roVideoPlayer with roCaptionRenderer in custom mode. This application was working just fine until now. But now sometimes it starts to play captions from the previous clip in the list on current video and sometimes starts to work just fine. As far as I know we have no control over subtitles even in custom mode of roCaptionRenderer so there must be a glitch in the firmware because of which this is happening? I have checked the list of videos and subtitles that I am feeding to roVideoPlayer it has correct pairs of video + subtitles.

Edit:
What I have found out is if some video is not played by any reason no availabilty, no url given etc but its subtitles is fine then its subtitle is played with next video and then this keeps happening till the end of the video list.
0 Kudos
10 Replies
destruk
Level 10

Re: Captions Problem!

Maybe you need to check for a playback failure and then clear the caption for the failed video. Or rather than feeding it an entire content playlist, feed it one caption and one video at a time until the list is completed.
0 Kudos

Re: Captions Problem!

"destruk" wrote:
Maybe you need to check for a playback failure and then clear the caption for the failed video. Or rather than feeding it an entire content playlist, feed it one caption and one video at a time until the list is completed.


Thanks for the suggestions, I do not think first solution is possible as, as far as I know we cannot clear captions ourself as these are sent as event message to us by Roku firmware. Second option can be implemented but why should we play our content one by one when roVideoPlayer supports a list of content? Shouldn't this issue be handled by roVideoPlayer itself?
0 Kudos
destruk
Level 10

Re: Captions Problem!

To check for playback failure, in your wait routine in the video player section in Brightscript, add an If msg.isRequestFailed() Then

isRequestFailed() as Boolean
Video playback has failed.

GetMessage() as String
Returns text description of error.

GetIndex() as Integer
Returns one of the following error IDs:

0 Network error : server down or unresponsive, server is unreachable, network setup problem on the client.
-1 HTTP error: malformed headers or HTTP error result.
-2 Connection timed out
-3 Unknown error
-4 Empty list; no streams were specified to play
-5 Media error; the media format is unknown or unsupported

http://sdkdocs.roku.com/display/sdkdoc/ ... layerEvent


For feeding it one item to play at a time - use a simple loop before calling videoplayer -
such as...
in the springboard screen where you have your wait loop for the springboard screen -
iSelected=0


If msg.isListItemSelected()
iSelected=msg.GetIndex()
Currentkid=Categories.Kids[iSelected]
If UCASE(Currentkid.title)="LOOP" Then EngageLooping()


Function engagelooping()
conn=CreateObject("roAssociativeArray")
conn.UrlCategoryFeed="http://server/looping.xml"
conn.LoadCategoryFeed=load_show_feed
Categories=conn.LoadCategoryFeed(conn)
list=CreateObject("roArray",1,TRUE)
For i=0 to (Categories.Kids.Count()-1) 'this will need to be adjusted to fit your feed xml schema
list.Push(Categories.kids[i])
Next
rcanvas=CreateObject("roImageCanvas") 'create black screen to hide the springboard when any video ends and starts playing next video
rcanvas.show()
inz=-1 'initialize single counter for single video in list
checking:
inz=inz+1 'increment counter
if inz=list.count() inz=0 'reset counter to loop list
result=ShowVideoScreenLOOP(list[inz]) 'send current single video item to video player
if result=0 goto checking 'loop back to checking routine
rcanvas.close() 'loop is finished, so close canvas mask
End Function


Referring back to checking for failure - as long as your video player function returns 0 in this case, it will loop to the next video endlessly until Home is pressed.
If your video fails, or the user presses UP to cancel playback, you should have it return something other than 0. And you can check the return values to see what happened where it says if result=0
So if result=1 then they press up and you should close the screen (for instance)


Finally, yes, if it is a confirmed bug in the roVideoPlayer component itself, then Roku should file a bug and fix it themselves -- not having seen any of your code you are using, it sounds like it's probably not replacing the SRT for the appropriate piece of content somewhere - whether that is in your code or the component yourself I don't have tools to test that as I haven't ever used SRT files myself - we prefer to burn subtitles overlaid into a separate video file so we don't need to deal with it.
0 Kudos
destruk
Level 10

Re: Captions Problem!

"as far as I know we cannot clear captions ourself as these are sent as event message to us by Roku firmware."
"In firmware version 2.6, we've introduced support for SRT files. Please see the content meta-data parameter SubtitleUrl for pointing to a matching SRT file for your video content."

This means your xml feed should already have the location of the SRT files - roku doesn't 'magically obtain that' -- it's set manually just like the other content-metadata like HDPosterURL/SDPosterURL/Streams/etc etc
You can clear the url yourself by setting it to invalid, or resetting the url -
In the example above -

Categories.Kids[iSelected].SubititleURL=invalid

or

Categories.Kids[iSelected].SubititleURL="http://server/subtitlefilename.srt"

Before sending it to the videoplayer screen.


With roCaptionrenderer here --
http://sdkdocs.roku.com/display/sdkdoc/ ... onRenderer
Your metadata is TrackIDSubtitle: "ism/textstream_eng"
so you should be able to change that with --
Categories.Kids[iSelected].TrackIDSubtitle="ism/subtitlefilename.eng"

If it is cached, you can try adding a cachebreaker by adding a variable to the filename or disabling caching on the server.
ism/subtitlefilename.eng?timestamp=283493843
0 Kudos

Re: Captions Problem!

"destruk" wrote:
To check for playback failure, in your wait routine in the video player section in Brightscript, add an If msg.isRequestFailed() Then

isRequestFailed() as Boolean
Video playback has failed.

GetMessage() as String
Returns text description of error.

GetIndex() as Integer
Returns one of the following error IDs:

0 Network error : server down or unresponsive, server is unreachable, network setup problem on the client.
-1 HTTP error: malformed headers or HTTP error result.
-2 Connection timed out
-3 Unknown error
-4 Empty list; no streams were specified to play
-5 Media error; the media format is unknown or unsupported

http://sdkdocs.roku.com/display/sdkdoc/ ... layerEvent


For feeding it one item to play at a time - use a simple loop before calling videoplayer -
such as...
in the springboard screen where you have your wait loop for the springboard screen -
iSelected=0


If msg.isListItemSelected()
iSelected=msg.GetIndex()
Currentkid=Categories.Kids[iSelected]
If UCASE(Currentkid.title)="LOOP" Then EngageLooping()


Function engagelooping()
conn=CreateObject("roAssociativeArray")
conn.UrlCategoryFeed="http://server/looping.xml"
conn.LoadCategoryFeed=load_show_feed
Categories=conn.LoadCategoryFeed(conn)
list=CreateObject("roArray",1,TRUE)
For i=0 to (Categories.Kids.Count()-1) 'this will need to be adjusted to fit your feed xml schema
list.Push(Categories.kids[i])
Next
rcanvas=CreateObject("roImageCanvas") 'create black screen to hide the springboard when any video ends and starts playing next video
rcanvas.show()
inz=-1 'initialize single counter for single video in list
checking:
inz=inz+1 'increment counter
if inz=list.count() inz=0 'reset counter to loop list
result=ShowVideoScreenLOOP(list[inz]) 'send current single video item to video player
if result=0 goto checking 'loop back to checking routine
rcanvas.close() 'loop is finished, so close canvas mask
End Function


Referring back to checking for failure - as long as your video player function returns 0 in this case, it will loop to the next video endlessly until Home is pressed.
If your video fails, or the user presses UP to cancel playback, you should have it return something other than 0. And you can check the return values to see what happened where it says if result=0
So if result=1 then they press up and you should close the screen (for instance)


Finally, yes, if it is a confirmed bug in the roVideoPlayer component itself, then Roku should file a bug and fix it themselves -- not having seen any of your code you are using, it sounds like it's probably not replacing the SRT for the appropriate piece of content somewhere - whether that is in your code or the component yourself I don't have tools to test that as I haven't ever used SRT files myself - we prefer to burn subtitles overlaid into a separate video file so we don't need to deal with it.



Thank you for the detailed reply. I know about isRequestFailed function, this can be used to tackle the current situation if we send videos one after another ourselves like you did in your code. I am working to shift my code to this scenario but previously I was giving a complete list of videos to roVideoPlayer using its SetContentList method. In this case of list isRequestFailed cannot be used because we will not be able to remove this video from the playlist that is already passed to roVideoPlayer along with its subtitle.

And to your other reply:

As you said you have not worked with subtitles yet so you might not know that we must need to give subtitle url along with video playback url and I am doing this too. Secondly, we do not process these subtitles file further in any way ourselves even not in custom mode of roCaptionRenderer. roCaptionRenderer generates roCaptionRendererEvent's frequently and send us the current caption to show (1 line of text for current time of video playback) in its event's message and I print this caption on screen myself.

So once I have passed a list to roVideoPlayer I have no control over subtitles or which subtitles file should be played with which video.

My video list for roVideoPlayer is in this format:
videoList = CreateObject("roArray", 1, true)
for each vid in json.videos
video = CreateObject("roAssociativeArray")
video.title = vid.title
video.streamFormat = vid.type
video.stream = CreateObject("roAssociativeArray")
video.stream.url = vid.url
video.stream.bitrate = 1500
video.stream.quality = true
video.stream.contentId = vid.content_id
video.subtitleUrl = vid.subtitle_url
videoList.Push(video)
end for


subtitles + video pairs sent by server in json.videos are correct. So this is as far as I have control over subtitles and until here everything is working fine.

So when the problem comes:
when this video list has a video for which video.stream.url is invalid but video.subtitleUrl is valid like

video = CreateObject("roAssociativeArray")
video.title = vid.title
video.streamFormat = vid.type
video.stream = CreateObject("roAssociativeArray")
video.stream.url = invalid
video.stream.bitrate = 1500
video.stream.quality = true
video.stream.contentId = vid.content_id
video.subtitleUrl = vid.subtitle_url


Then whole of this video should be skipped but this does not happen and for next video in the list subtitleUrl of this video is used.

and now about code, below is the my code to initialize roVideoPlayer:

videoPlayer.SetMessagePort(port)
videoPlayer.SetDestinationRect(playerRect)
videoPlayer.SetPositionNotificationPeriod(1)
videoPlayer.SetMaxVideoDecodeResolution(1920, 1080)
videoPlayer.SetLoop(false)

captions = videoPlayer.GetCaptionRenderer()
captions.SetMode(2)
captions.SetMessagePort(port)
captions.ShowSubtitle(true)

videoPlayer.SetCertificatesFile("common:/certs/ca-bundle.crt")
videoPlayer.SetCertificatesDepth(4)
videoPlayer.InitClientCertificates()

videoPlayer.SetContentList(videoList)


Here is the relevant code from my event loop:

while true
msg = wait(0, m.port)
if msg <> invalid
if type(msg) = "roCaptionRendererEvent"
if msg.isCaptionText()
caption = msg.GetMessage()
m.captionTextList = caption.Tokenize(chr(10)) ' char(10) is newline
end if
end if
if type(msg) = "roUniversalControlEvent"
' http://sdkdocs.roku.com/display/sdkdoc/roUniversalControlEvent
if msg.GetInt() = 0 'back button is pressed
return 1
else if msg.GetInt() = 10 'info/* button is pressed
m.videoPlayer.Pause()
m.screen = invalid
userChoice = m.showOptionsDialog()
if userChoice = 0
return 3
else if userChoice = 1
return 4
end if
m.screen = CreateObject("roScreen", true)
m.screen.SetMessagePort(m.port)
m.screen.SetAlphaEnable(true)
m.videoPlayer.Resume()
end if
else if type(msg) = "roVideoPlayerEvent"
if msg.GetMessage() = "start of play" OR msg.isPlaybackPosition()
if m.isLoadingVideo = true
m.isLoadingVideo = false
m.drawScreen()
end if
else if msg.GetMessage() = "startup progress"
if m.isLoadingVideo <> true
m.isLoadingVideo = true
m.drawScreen()
end if
else if msg.GetMessage() = "Playback completed."
return 2
end if
end if
end if
end while
0 Kudos
destruk
Level 10

Re: Captions Problem!

I would think something like this would work for your situation, still using the playlist -
I haven't tested it but the logic makes sense to me.

currentvideo=0 goes before your event loop starts for the video player (in the video player routine)
The code in the event loop goes into your event loop for the video player routine.


currentvideo=0 'initialize counter -- maybe this isn't necessary but it is here for legibility so I know later it will be an integer and what it is used for
....event loop....
else if type(msg) = "roVideoPlayerEvent"
If msg.isrequestfailed()
errormessage=msg.info()
playlist=videoPlayer.GetContentList()
for x=0 to playlist.count()-1
If errormessage.url=playlist[X].stream.url then 'once bad stream has been found, no need to search for it so break out of the for loop
currentvideo=X
exit for
end if
next
for x=0 to currentvideo 'it failed so delete everything that has already played as well as current video that tried to play
playlist.delete[X]
next
if playlist.count()>0 'if there are items left to play
videoPlayer.SetContentList(playlist)
videoPlayer.Show() 'might not be necessary, but show the screen again to restart the videos with the altered new playlist
end if
end if
0 Kudos
destruk
Level 10

Re: Captions Problem!

If you need it to loop (always something, right?) then rather than deleting everything up to the point of failure in the playlist, you could remove just the failed item, track what item was removed, and reset the playlist followed by SetNext to restart where it left off with the next piece of valid content.
http://sdkdocs.roku.com/display/sdkdoc/ ... egerasVoid

SetNext(item as Integer) as Void
Set what the next item to be played within the Content List should be.

I'd still recommend deleting the entire piece of bad content so the number of subtitle urls that are valid will match up with the number of valid video urls - as that seems to be the problem for the rovideoplayer/rocaption
0 Kudos

Re: Captions Problem!

"destruk" wrote:
I would think something like this would work for your situation, still using the playlist -
I haven't tested it but the logic makes sense to me.

currentvideo=0 goes before your event loop starts for the video player (in the video player routine)
The code in the event loop goes into your event loop for the video player routine.


currentvideo=0 'initialize counter -- maybe this isn't necessary but it is here for legibility so I know later it will be an integer and what it is used for
....event loop....
else if type(msg) = "roVideoPlayerEvent"
If msg.isrequestfailed()
errormessage=msg.info()
playlist=videoPlayer.GetContentList()
for x=0 to playlist.count()-1
If errormessage.url=playlist[X].stream.url then 'once bad stream has been found, no need to search for it so break out of the for loop
currentvideo=X
exit for
end if
next
for x=0 to currentvideo 'it failed so delete everything that has already played as well as current video that tried to play
playlist.delete[X]
next
if playlist.count()>0 'if there are items left to play
videoPlayer.SetContentList(playlist)
videoPlayer.Show() 'might not be necessary, but show the screen again to restart the videos with the altered new playlist
end if
end if


Thanks for the code representation of the solution to the problem it seems that it will work according to logic. I will implement it and then will post if any else issue came. Thanks once again for your help.
0 Kudos

Re: Captions Problem!

"destruk" wrote:
If you need it to loop (always something, right?) then rather than deleting everything up to the point of failure in the playlist, you could remove just the failed item, track what item was removed, and reset the playlist followed by SetNext to restart where it left off with the next piece of valid content.
http://sdkdocs.roku.com/display/sdkdoc/ ... egerasVoid

SetNext(item as Integer) as Void
Set what the next item to be played within the Content List should be.

I'd still recommend deleting the entire piece of bad content so the number of subtitle urls that are valid will match up with the number of valid video urls - as that seems to be the problem for the rovideoplayer/rocaption


I have added the filter on my server side to exclude videos that does not have a playback URL but I was keen to reach a permanent solution because this issue happens even if a valid url could not be played because of any reason. So I will edit my event loop to make it more reliable and delete all the content till bad URL as I do not need to loop same list. I hope that Roku team removes this issue as it seems to be issue in their firmware. Thanks
0 Kudos