Javascript MediaSource API和H264视频

Javascript MediaSource API和H264视频,javascript,video,video-streaming,html5-video,media-source,Javascript,Video,Video Streaming,Html5 Video,Media Source,我在使用javascript MediaSource扩展API播放H264视频时遇到问题 我将在下面详细描述该场景 我已经成功地实现了播放音频和视频源的效果 对于vp8、vp9、opus和vorbis编解码器,也可以从范围请求(如果服务器有能力,使用任何字节范围)或分块文件,分块使用shaka packager完成 当源是H264视频时,问题就出现了,在我的例子中有详细说明 编解码器为avc1.64001e和mp4a.40.2,完整编解码器字符串为 视频/mp4;codecs=“avc1.640

我在使用javascript MediaSource扩展API播放H264视频时遇到问题

我将在下面详细描述该场景

我已经成功地实现了播放音频和视频源的效果 对于vp8、vp9、opus和vorbis编解码器,也可以从范围请求(如果服务器有能力,使用任何字节范围)或分块文件,分块使用shaka packager完成

当源是H264视频时,问题就出现了,在我的例子中有详细说明 编解码器为avc1.64001e和mp4a.40.2,完整编解码器字符串为 视频/mp4;codecs=“avc1.64001e,mp4a.40.2”但任何其他avc1编解码器仍存在此问题

我想做的是播放一段10兆字节的完整视频, byterange curl请求生成的块,使用-o在本地保存响应

下面是shaka packager将此文件作为输入传递的流信息

[0530/161459:INFO:demuxer.cc(88)] Demuxer::Run() on file '10mega.mp4'.
[0530/161459:INFO:demuxer.cc(160)] Initialize Demuxer for file '10mega.mp4'.

File "10mega.mp4":
Found 2 stream(s).
Stream [0] type: Video
 codec_string: avc1.64001e
 time_scale: 17595
 duration: 57805440 (3285.3 seconds)
 is_encrypted: false
 codec: H264
 width: 720
 height: 384
 pixel_aspect_ratio: 1:1
 trick_play_factor: 0
 nalu_length_size: 4

Stream [1] type: Audio
 codec_string: mp4a.40.2
 time_scale: 44100
 duration: 144883809 (3285.3 seconds)
 is_encrypted: false
 codec: AAC
 sample_bits: 16
 num_channels: 2
 sampling_frequency: 44100
 language: und

Packaging completed successfully.
区块可通过外部媒体播放器应用程序(如VLC)播放 更重要的是,使用标签将其添加到网页时不会出现问题。

这是我在Chrome控制台中看到的错误

Uncaught (in promise) DOMException: Failed to load because no supported source was found.
下面是html和js代码(我使用内置的php7.2开发服务器进行了所有本地测试)


视频测试
录像带{
宽度:98%;
高度:300px;
边框:0px实心#000;
显示器:flex;
}
下面是JS代码(scripjs)

classmediatest{
构造函数(){
}
初始化(链接){
this.link=link;
this.media=new MediaSource();
this.container=document.getElementsByTagName('video')[0];
this.container.src=window.URL.createObjectURL(this.media);
返回新承诺(解决=>{
this.media.addEventListener('sourceopen',(e)=>{
this.media=e.target;
返回解析(本);
});
});
}
addSourceBuffer(){
让编解码器='video/mp4;codecs=“avc1.64001e,mp4a.40.2”;
让sourceBuffer=this.media.addSourceBuffer(编解码器);
//这些标题与标记发送的标题相同
//不管有没有这个问题仍然存在
让标题=新标题({
“范围”:“字节=0-131072”,
“接受编码”:“标识;q=1,*;q=0”
});
让requestData={
标题:标题
};
let request=新请求(this.link,requestData);
返回新承诺(解决=>{
获取(请求)。然后((响应)=>{
如果(200!==响应状态){
抛出新错误('addSourceBuffer错误,状态为'+response.status');
}
返回响应。arrayBuffer();
})。然后((缓冲)=>{
sourceBuffer.appendBuffer(buffer);
log('Buffer added');
返回解析(本);
}).catch(函数(e){
log('addSourceBuffer error');
控制台日志(e);
});
});
}
play(){
this.container.play();
}
}
window.addEventListener('load',()=>{
let media=new MediaTest();
media.init('/media/10mega.mp4')。然后(()=>{
log('init ok');
返回媒体。addSourceBuffer();
}).然后((obj)=>{
console.log('play');
媒体播放();
});
});
我想要实现的是使用MediaSourceAPI播放文件,因为它使用标记播放效果很好。 我不想对它进行解复用和重新编码,但请按原样使用它

下面是从中获取的错误转储chrome://media-internals

渲染id:180玩家id:11管道状态:kStopped事件: 网络媒体播放器

为了重现,我认为可以使用任何包含音频和视频轨迹的H264视频

这个问题与我发现的另一个问题有着严格的联系,但这是4年前的问题,所以我决定不在这里回答

有人知道这个问题吗? 有没有办法解决它或者h264它与MSE不兼容


提前感谢

这不是编解码器,而是容器。MSE需要碎片化的mp4文件。不支持标准mp4。对于标准mp4,您必须使用

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>VideoTest</title>
    <link rel="icon" href="/favicon.ico" />
    <script type="text/javascript" src="/script.js"></script>

    <style>
        video {
            width: 98%;
            height: 300px;
            border: 0px solid #000;
            display: flex;
        }
    </style>
</head>
<body>

<div id="videoContainer">
    <video controls></video>
</div>

<video controls>
    <source src="/media/10mega.mp4" type="video/mp4">
</video>

</body>
</html>
class MediaTest {
    constructor() {

    }

    init(link) {
        this.link = link;
        this.media = new MediaSource();
        this.container = document.getElementsByTagName('video')[0];
        this.container.src = window.URL.createObjectURL(this.media);

        return new Promise(resolve => {
            this.media.addEventListener('sourceopen', (e) => {
                this.media = e.target;
                return resolve(this);
            });
        });
    }

    addSourceBuffer() {
        let codec = 'video/mp4;codecs="avc1.64001e, mp4a.40.2"';
        let sourceBuffer = this.media.addSourceBuffer(codec);

        // These are the same headers sent by the < source > tag
        // with or without the issue remains
        let headers = new Headers({
            'Range': 'bytes=0-131072',
            'Accept-Encoding': 'identity;q=1, *;q=0'
        });

        let requestData = {
            headers: headers
        };
        let request = new Request(this.link, requestData);

        return new Promise(resolve => {
            fetch(request).then((response) => {
                if(200 !== response.status) {
                    throw new Error('addSourceBuffer error with status ' + response.status);
                }

                return response.arrayBuffer();
            }).then((buffer) => {
                sourceBuffer.appendBuffer(buffer);
                console.log('Buffer appended');
                return resolve(this);
            }).catch(function(e) {
                console.log('addSourceBuffer error');
                console.log(e);
            });
        });
    }

    play() {
        this.container.play();
    }
}

window.addEventListener('load', () => {
    let media = new MediaTest();
    media.init('/media/10mega.mp4').then(() => {
        console.log('init ok');
        return media.addSourceBuffer();
    }).then((obj) => {
        console.log('play');
        media.play();
    });
});