如何检测一个视频文件是否支持HTML5视频标签

How to detect if a video file is supported by the HTML5 video tag?

本文关键字:视频 是否 文件 HTML5 标签 支持 何检测 检测 一个      更新时间:2023-09-26

我有一个JavaScript文件对象在用户的机器上,我想链接到它的video标签和播放它。问题是,我需要先检测浏览器是否支持我的文件的编解码器,我该怎么做?我知道我可以用canPlayType()函数检测浏览器支持的编解码器,但是我如何检测我拥有的文件的编解码器?

我已经研究了更多,canPlayType()也可以包含编解码器,所以你可以尝试:

canPlayType('video/mp4; codecs="avc1.42E01E"');

canPlayType('video/mp4; codecs="mp4a.40.2"');

,例如

"我有一个JavaScript的File对象的文件在用户的机器…我知道我可以用canPlayType()函数检测浏览器支持的编解码器,但是我如何检测我拥有的文件的编解码器?"

(1)如果编解码器已知…使用canPlayType检查编解码器兼容性

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)如果编解码器未知…检查文件字节的编解码器类型(然后执行步骤(1)以确认可播放性)

这意味着获取文件字节的一个块(例如获取第一个64kb或最后64kb,取决于MP4头是在文件的前面还是后面)。

将数据读取到数组中,然后搜索该数组的stsd部分,这是MP4保持H264数据的序列参数集(SPS)的地方,从该部分您可以提取编解码器信息。

a)找到stsd的位置。
b)从该位置跳过+16字节以找到avc1hev1
c)从+16 pos,从这里的+91跳转到SPS(3字节)。

下面是一个使用选定(本地)文件的示例,该文件通过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>