'How to detect if a video file is supported by the HTML5 video tag?
I have a File object in JavaScript of a file in the user's machine and I want link to it in a video
tag and play it. The problem is that I need to detect first if the browser supports the codec of the file I have, how do I do that? I know I can detect what codecs the browser supports with the canPlayType()
function, but how can I detect the codec of the file I have?
Solution 1:[1]
I've looked into it more, and canPlayType() can also contain the codec, so you can try:
canPlayType('video/mp4; codecs="avc1.42E01E"');
and
canPlayType('video/mp4; codecs="mp4a.40.2"');
separately for example
Solution 2:[2]
"I have a File object in JavaScript of a file in the user's machine... I know I can detect what codecs the browser supports with the canPlayType()
function, but how can I detect the codec of the file I have?"
(1) If codec is known... Use canPlayType
to check codec compatibility.
var vid = document.getElementById("myVideoElementID");
//# for AVC1 codecs like avc1.42E01E
if( vid.canPlayType('video/mp4; codecs="avc1"') )
{ alert("can play AVC1 / H.264 "); }
(2) If codec is unknown... Check file bytes for codec type (then do step (1) to confirm playability)
This means getting a chunk of the file's bytes (for example getting the first 64kb or last 64kb, depends if MP4 header is at front or back of file).
Read the data into an Array and then search that Array for the stsd
section, which is where MP4 keeps the Sequence Parameter Set (SPS) of the H264 data, from that section you can get extract the codec info.
a) Find stsd
position.
b) From that position, skip +16
bytes to find either avc1
or hev1
.
c) From the +16
pos, skip forward from here +91
to get the SPS (3 bytes).
Here is an example using a selected (local) file which is read into an Array via FileReader API.
<!DOCTYPE html>
<html>
<body>
<!-- button Choose MP4 Video -->
<div style="z-index: 1; overflow:hidden; position: absolute; top: 18px; left: 10px; " >
<text> <b> Choose a Video (.MP4) file...</b> <br>
<input type="file" id="choose_video" accept=".mp4" />
</div>
<video id="myVideo" width="640" height="480" controls style="position: absolute; top: 80px; left: 10px; " >
<source src="" type="video/mp4">
</video>
</body>
<script>
var temp_int = 0; var temp_str = ""; var temp_arr = [];
var reader; var path;
var fileBytes; //# is updated to: uint8Array []
var file; //# a File object (using Reader)
//# codec name (is String object)
var str_codec = "-1";
var myvid = document.getElementById( 'myVideo' );
addEventListener("load", on_page_Ready );
function on_page_Ready()
{
//# listener for selecting MP4 file
document.getElementById('choose_video').addEventListener('change', onSelectFile, false);
}
function onSelectFile(evt)
{
file = evt.target.files[0]; //# FileList object
path = (window.URL || window.webkitURL).createObjectURL(file);
reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function(evt)
{
if (evt.target.readyState == FileReader.DONE)
{
fileBytes = new Uint8Array( evt.target.result );
//# extract codec info
get_MP4_Codec( fileBytes );
//# load video data and play ...
myvid.setAttribute("src", path);
myvid.load();
myvid.play();
}
}
}
function get_MP4_Codec (inBA)
{
let idx = 0; //# index (position) in bytes
while(true)
{
//# auto stop if "stsd" not found after 32 kilobytes
if ( (idx > 32000) || (idx >= inBA.length-1) ) { break; }
//# look for starting "s" (is byte value 0x73)
if( inBA[ idx ] == 0x73 ) //# find "s"
{
//# check if next following 3 bytes are the required values
if( (inBA[ idx+1 ] == 0x74) && //# find "t"
(inBA[ idx+2 ] == 0x73) && //# find "s"
(inBA[ idx+3 ] == 0x64) //# find "d"
)
{
//# when found...
//# note the "stsd" position
temp_int = idx;
//# skip forward by 16 bytes to get codec type
//# codec type can be "avc1" or "hev1" or "hvc1"
idx += 16;
str_codec = String.fromCharCode( inBA[ idx+0 ] );
str_codec += String.fromCharCode( inBA[ idx+1 ] );
str_codec += String.fromCharCode( inBA[ idx+2 ] );
str_codec += String.fromCharCode( inBA[ idx+3 ] );
//# need that dot "." also
str_codec += ".";
//# skip forward by 91 bytes to get codec SPS details
//# example"avc1.64001f" the SPS is "64001F"
idx += 91;
temp_str = (inBA[idx].toString(16)).toUpperCase();
str_codec += temp_str.length === 2 ? temp_str : '0' + temp_str;
idx += 1;
temp_str = (inBA[idx].toString(16)).toUpperCase();
str_codec += temp_str.length === 2 ? temp_str : '0' + temp_str;
idx += 1;
temp_str = (inBA[idx].toString(16)).toUpperCase();
str_codec += temp_str.length === 2 ? temp_str : '0' + temp_str;
break;
}
}
idx++;
}
alert("found STSD @ byte pos : " + temp_int +"\n"+ "codec type : " + str_codec );
}
</script>
</html>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Ian Devlin |
Solution 2 | VC.One |