How do I stream a video of initially unknown size to the HTML5 video tag? - html

I am attempting to write a web service (using C# and WebAPI, thought the actual server technology likely isn't important) that hosts dynamic video files for consumption by a basic HTML5 video element.
Here is my situation and my requirements:
The video is being transcoded on the fly and so the final file size is not known. I cannot provide a Content-Length. However, the time duration of the video is known in advance.
The video must be immediately playable when the page loads, even if it's not done transcoding.
The user must be able, via the HTML5 video controls, to seek backwards and forwards in the video. If they attempt to seek forward to a point that is not transcoded, the request will block until the transcoding catches up.
I tried to use a 206: Partial Content response with the Content-Range header but since I am unable to provide a content-length, the player in Chrome seems unable to seek beyond the first chunk of video it gets and the player in Firefox doesn't even attempt to download more than the first chunk. It is also invalid to respond with a range outside what is asked for by the client but the video player always asks for bytes 0+.
Without a content-length, I considered using Transfer-Encoding: chunked and chunking the output. However, Chrome does not let you seek through a video if the server does not support ranged requests.
I have also considered specifying a fake content length of 1TB or something ridiculous just so I can do the ranged response option but I do not know if that will affect the progress bar or seek capabilities. Does the HTML5 video player determine the progress bar's dimensions based on file size or duration?
So what are my options? I am sure this is a problem that's been solved before. Can ranged responses be used in conjunction with chunked encoding?

Related

Streaming from HTML audio tag not buffering file

I'm building a page with audio streaming and I need to fast-forward and backward the audio. I'm working with the native <audio> HTML element.
I don't know why the audio isn't buffering, therefore I can't play with the currentTime property. If I use another streaming URL from another random radio it works. So I guess is related to something with the stream server.
I have many questions:
1 - What is causing the streaming not to buffering?
2 - Is something related to the audio format? AAC or MP3?
This is my audio not buffering:
And this another audio (from other web) that buffer correctly:
Edit: I have another clue. The stream that doesn't buffer is in AAC format and the one that its buffer is in MP3 format. Does anyone know if the format has something to do whith buffering?
I would guess the server submitted response is not compatible with disk caching which is probably used to implement the buffering.
Things that I would check:
Server accepts Range headers with byte offsets.
Server responds with Content-Range header with correct byte offsets for the content. Make sure the response if not off-by-one if you have custom implementation. Note that HTTP spec uses weird interpretation for the offsets and length!
HTTP Status code should be 206 instead of 200 if the request contains header Range.
The response should contain header ETag which should be static as long as the media file is the same.
The response should contain header Cache-Control with suitable value. For details, see HTTP Headers: Controlling Cache and History Mechanism
Can you repeat the problem with different browser engines? For example, test with Firefox, Chrome and Safari – do they behave the same or are you dealing with some browser specific behavior.

How to download (or get as a blob) a MediaSource used for streaming HTML5 video?

I'm streaming a dynamically-generated MP4 into a webpage over a WebSocket. I assemble a MediaSource (https://developer.mozilla.org/en-US/docs/Web/API/MediaSource) as the fragments come in, use that for the HTML5 video element, and my video plays fine in all major browsers.
What I'd like to do is add the ability for a user to download this video. My first attempt was to see if I could get access to it through the video.src property, which I set with window.URL.createObjectURL(my_media_source). This URL is a blob URL of the form "blob:null/abb348e0-3459-8344-bf1e-063dd001f09a". I don't know why there is a null in that url, but it is consistently there. An XMLHttpRequest to get this blob fails.
So, what is the right way to take my streaming video that plays fine and download it as a single file? The MediaSource seems to contain the entire video stream -- can I get access to that as an arraybuffer or a blob or whatever?
I think I answered this on my own. To my understanding, here is the present situation:
First off, it appears that getting the binary data back from a MediaSource is actually not currently possible. There is even an issue about this on the W3C standard: https://github.com/w3c/media-source/issues/209
What is possible is using the relatively new MediaRecorder (https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder) API, which is not yet supported by all browsers. The downside of this is that the browser re-encodes the video and you have less control over the output format -- I couldn't get Chrome to produce an mp4, only a webm. Also, if there was a previous request for binary data, every time you request the binary data, it will only give you the data starting from that previous request.
Of course, one could also manually keep a second copy of the video in memory, but I didn't want to follow that approach as it seemed very wasteful and annoying.

How do I prevent HTML5 video from buffering the entire video once you click play?

Is there a way to control how much of the file will be buffered ahead, once you click play, much like Youtube once did?
If you use the built-in video support in the browser then there is no way to control the amount of data that's being buffered. It depends on the browser implementation and there is no API to control it.
Browser implementations are quite good and typically a browser buffers just a small portion of the video before playback begins. Browsers don't download the whole file. However if a file gets completely downloaded by the browser before playback begins then possible causes include:
Maybe the file is very small and the browser has decided to buffer the whole file in memory.
Maybe the header of the file (required to initialize the video decoder) is not at the start of the file but at the end and the browser has to download the whole file until it reaches it. This is uncommon nowadays but old video encoders used to place the mp4 header at the end of the file instead of at the beginning because it simplified the encoder's implementation.
I've noticed that browsers behave oddly if an mp4 file doesn't have a segment index (used for seeking) in its header. Some browsers download the whole file so that they can build a segment index themselves.
If your server is old/misconfigured then the browser may decide that range requests are not supported and download the whole file (or disable seeking).
If you require to control the buffered amount before playback begins then you have to use a more sophisticated protocol (MPEG-DASH, HLS) and a javascript player that allows you to control this parameter. Youtube use MPEG-DASH and have their own player that they've developed over the years.
I'm pretty sure you c an't stop the HTML5 video from buffering the entire video, but here is a useful link for working out how much of the video has been buffered.
https://developer.mozilla.org/en-US/Apps/Build/Audio_and_video_delivery/buffering_seeking_time_ranges
Like mylescc mentioned, preventing the video element from buffering might not be possible, without a workaround (described in a similar posting). However, depending on your use case, you can also make use of existing player implementations, which provide this functionality, like the bitmovin player, dash.js, etc.

Video file being accessed twice on mobile device

I'm working on my own DRM solution for video content. I'm verifying each access to the actual video file. So video.mp4 is actually video.php which then streams orig_vid.mp4 into a <video> element.
It works fine and all – except on mobile! Mobile seems to access the video file two times, making the second request unverifiable.
Before the video is played (autoplay not possible on mobile) it accesses the file once, probably to get headers, etc. Then another request is coming throug, once we hit the play button (as expected), but after that, there's another request, and I can't figure out why or how to validate this request.
If at least I know the pattern behind the requests, I could build my script so it accommodates those. But to me right now the 2 requests seem random...
Any idea or explanation why that is or what's going on?
Are there Cache-Control, Date and Expires headers properly set?

Accurate Seek in Pseudo-streaming Flash

I would like to know if the flash fallback (medialement or any other) can support accurate seek to the frame for an H.264 video in a MP4 container, transferred by HTTP using an IIS or apache web server (HTTP Pseudostreaming or Progressive Download). In HTML5, we can order to seek to any frame number and it will manage to decode whatever is needed to display the requested frame index.
Currently, what I can experiment with all flash player is something like a seek to the closest GOP or keyframe. However, this is unfortunately not enough for my project as I really need to be able to reach any arbitrary frame.
Do you know if there is a way to have an frame accurate seek in Flash, using HTTP pseudo streaming (I know this is possible with FMS and RTMP streaming).