This may seem like a super basic question, but I just can't figure it out! 😂
One the app I am creating I am using a basic Video xml element to play a given video, however I need to be able to check to see if I get a 404 when trying to play a video. The problem lies in the fact that the Video object will just repeatedly request a video from my server even if it only gets 404s back.
So, I decided to swap to a `roVideoPlayer` object instead since it gives me more control and can hopefully tell me what the response code of the given video is, that way I can have the player stop playing and display an error message if it gets a 404. The problem is that I just CAN NOT get the `SetContentList` function working! No matter how many different combinations of arrays, associative arrays, etc. I try, it just tells me that "Interface not a member of BrightScript Component". I've checked the 3+ sources of documentation and scoured the forum, but I just can't figure it out. As far as I know, it's supposed to be an array of `roAssociativeArray`s, and each associative array contains the details of a video to be played.
My code has been multiple different variations of this, but never works:
```video = { Title: "Video Title", Stream: { url: videoUrl }, StreamFormat: "mp4" } videoPlayer.SetContentList([video])```
Alternatively, if there is a way to check if a Video SceneGraph element fails to play a video due to a 404 error being returned from the server, that would solve the original problem.
Thank you for your help 🙂
Is there a reason why you're using SetContentList and not just SetContent?
For a video node, do you have an observer on the "state" of the video node? It should fire on any error.
SetContentList is the function mentioned in the documentation, although I have tried SetContent. In terms of observing the state of the Video player, I can observe that it is buffering, playing, paused, etc. my problem is that I can't detect if its getting a 404 when trying to buffer a non-existent video.
Thank you for help btw
I don't know why your "state" observer isn't working. I tried setting the URL to a nonexistent video on my server and my server returned a 404, my "state" observer fired, GetData() returned "error". and my video node "errorCode" was set to 404.
Edit: "errorCode" is set to -1. "errorStr" shows the 404.
Is that for a `roVideoPlayer` object or a `roSGNode` that represents a Video SceneGraph element? I have a "state" observer on the `roSGNode` for my video element, but it doesn't fire with errors, it just fires for states like "buffering", "paused", "playing", etc.
That's for a Video node. My "onState" observer function fires first with "buffering" and then with "error" when I set the URL to a nonexistent file. I've also used observers with message ports and waited on the port in the main thread. That looks something like this:
Function displayVideo(video as Object) as Integer
print "Displaying video: "; video["url"]
vn = m.video_node
vc = createObject("roSGNode", "ContentNode")
vc.url = video.url
vc.StreamFormat = video.StreamFormat
print vn.observeField("position", m.port)
print vn.observeField("control", m.port)
print vn.observeField("state", m.port)
vn.content = vc
vn.setFocus(true)
vn.control = "play"
while true
msg = wait(0,m.port)
msgtype = type(msg)
print msgtype
if msgtype = "roSGNodeEvent" then
node = msg.GetNode()
field = msg.GetField()
data = msg.GetData()
print node, field, data
if field = "position" then
position = data
else if field = "control" and data = "stop" then
exit while
else if field = "state" then
if data = "finished" then
exit while
else if data = "buffering" then
m.video_screen.visible = true
else if data = "error" then
print vn.errorCode
print vn.errorMsg
print vn.errorStr
print vn.errorInfo
else if data = "playing" then
'
else if data = "paused" then
'
end if
end if
else if msgtype = "roSGScreenEvent" then
print msgtype, msg.GetData(), msg.isScreenClosed()
vn.control = "stop"
exit while
end if
end while
vn.control = "stop"
print vn.unobserveField("position")
print vn.unobserveField("control")
print vn.unobserveField("state")
return position
End Function
and produces this output:
roSGNodeEvent
video control play
roSGNodeEvent
video state buffering
roSGNodeEvent
video state error
errorCode: -1
errorMsg: There was an error in the HTTP response. This could mean that malformed HTTP headers or an HTTP error code was returned.
errorStr: reader pick stream error:HTTP error:HTTP server returned error code:404:extra:etype:buffer
errorInfo: <Component: roAssociativeArray> =
{
category: "http"
clipid: 1
dbgmsg: "reader pick stream error:HTTP error:HTTP server returned error code:404:extra:etype:buffer"
drmerrcode: 0
errcode: 2
ignored: false
source: "buffer:reader"
}
Wow, I didn't realize you could observe a field and then have it go to a port instead of a function... I still have a lot to learn about Roku app development 😂 So that works if I give the player a non-existent video to begin with, but say (and this is the issue I'm trying to resolve) that the video exists originally and then gets deleted while it's being played. That's when I can't detect that it's getting an error, it just thinks it's buffering.
However, I did find a workaround; every time the player starts buffering, I send a GET request to the same url and look at the response and then act accordingly. That way I can tell if the video stopped existing during playback. Really weird issue, I know.
I still wish I could get the `roVideoPlayer` working though, because the documentation says that when given a list of videos a `roVideoPlayer` will automatically pre-buffer the next video to make playback of a bunch of videos seamless. That would help me a lot, instead of taking videos and concatenating them on the server and then returning the result to the device. (I'm trying to basically show a bunch of ~15 second videos in a row on a TV seamlessly, almost like a slideshow).
Anyways, thank you @renojim SO much for helping out!
I don't know how much time you want to spend on roVideoPlayer. When I just tried to use it I got, "BRIGHTSCRIPT: WARNING: roVideoPlayer: This component is deprecated". I don't see that mentioned in the documentation for roVideoPlayer, but it is mentioned here. If you want to experiment, this works for me:
player = CreateObject("roVideoPlayer")
player.SetContentList([{
Stream: { url: "http://192.168.0.118/1.mp4" }
StreamFormat: "mp4"
},{
Stream: { url: "http://192.168.0.118/2.mp4" }
StreamFormat: "mp4"
},{
Stream: { url: "http://192.168.0.118/3.mp4" }
StreamFormat: "mp4"
},{
Stream: { url: "http://192.168.0.118/4.mp4" }
StreamFormat: "mp4"
},{
Stream: { url: "http://192.168.0.118/5.mp4" }
StreamFormat: "mp4"
}])
player.SetMessagePort(m.port)
player.SetLoop(true)
player.SetPositionNotificationPeriod(1)
player.Play()
while true
msg = wait(0, m.port)
if msg <> invalid then
print type(msg),msg.GetType(); ","; msg.GetIndex(); ": "; msg.GetMessage()
end if
end while
Roku SceneGraph is the recommended development platform, and there the Video node should be used.
https://developer.roku.com/docs/developer-program/core-concepts/core-concepts.md
https://developer.roku.com/docs/developer-program/core-concepts/playing-videos.md
Otherwise, as far as I know, roVideoPlayer is still supported for roScreen / 2D UI only.
(The deprecation notice has been there for many many years, but I believe it does not apply in that limited/unusual situation, but rather was intended to guide streaming channel developers to transition to SceneGraph.)
Thank you for your help! As it turns out, I actually was doing it correctly, but I had to create the `roVideoPlayer` on the main thread, which was what was causing me my problems.