javascript - 碎片化的 MP4 不显示在 Chrome 中

标签 javascript html google-chrome video video-streaming

但在 Firefox 中运行良好。

Google Chrome 版本:61.0.3163.100(正式版)(64 位)

Mozilla Firefox 版本:56.0.2(64 位)

我的视频是通过 WebSocket 流式传输到客户端 html 页面的分段 MP4,它被提取到 MSE 中。视频编解码器是 H264 Main Profile。视频信息已在 FFPROBE 和其他检查器中进行检查,以确保数据完整性正常。复用 FMP4 时使用以下标志:

 "empty_moov+default_base_moof+frag_keyframe"

我还仔细检查了第一个碎片是所谓的“初始化段”,大小为 24 字节。 正如我所说,Firefox 播放很好。

这是客户端代码(主要是从 here 借来的):

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>MSE Demo</title>
</head>

<body>
   <h1>MSE Demo</h1>
   <div>
      <video id="video1" controls width="80%"   autoplay="true"> </video>
   </div>
 <script type="text/javascript">
    (function () {

        var mime = 'video/mp4; codecs="avc1.4D401E"';

        if (!MediaSource.isTypeSupported(mime)) {
            document.querySelector('h1').append(' - Unsuported mime type :(');
            return;
        }

        var buffer;
        var websocket;
        var buffer_size = 4 * 1024 * 1024;
        var buffer_index = 0;
        var frag_mp4_buffer = new Uint8Array(buffer_size);
        var video = document.querySelector('video');
        var mediaSource = new MediaSource();

        mediaSource.addEventListener('sourceended', function (e) { console.log('sourceended: ' + mediaSource.readyState); });
        mediaSource.addEventListener('sourceclose', function (e) { console.log('sourceclose: ' + mediaSource.readyState); });
        mediaSource.addEventListener('error', function (e) { console.log('error: ' + mediaSource.readyState); });

        video.src = window.URL.createObjectURL(mediaSource);
        video.crossOrigin = 'anonymous';

        mediaSource.addEventListener('sourceopen', function (e) {
            console.log('sourceopen: ' + mediaSource.readyState);
             //doesn't help:
            //  var playPromise =  video.play();
            // In browsers that don’t yet support this functionality,
            // playPromise won’t be defined.
            /*
            if (playPromise !== undefined) {
                playPromise.then(function () {
                    // Automatic playback started!
                }).catch(function (error) {
                    // Automatic playback failed.
                    // Show a UI element to let the user manually start playback.
                });
            }
            */

            buffer = mediaSource.addSourceBuffer(mime);

            buffer.addEventListener('updateend', function (e) {
                if (video.duration && !video.currentTime) {
                    video.currentTime = video.duration;
                }
            });

            var websocket = new WebSocket('ws://' + document.location.hostname + ':8080');
            websocket.binaryType = 'arraybuffer';

            websocket.addEventListener('message', function (e) {
                var data = new Uint8Array(e.data);
                console.log("got packet! size:" + data.length);
                if (data.length) {
                    if ((buffer_index + data.length) <= buffer_size) {
                        frag_mp4_buffer.set(data, buffer_index);
                        buffer_index = buffer_index + data.length;

                        if (!buffer.updating && mediaSource.readyState == 'open')
                         {
                            var appended = frag_mp4_buffer.slice(0, buffer_index);
                            buffer.appendBuffer(appended);
                            frag_mp4_buffer.fill(0);
                            buffer_index = 0;

                        }
                    }
                }
            }, false);
        }, false);
    })();
    </script>
 </body>

另一个重要信息,你可以看到我注释掉了 video.play() 调用。这实际上是应用程序启动时唯一抛出错误的地方:

Uncaught (in promise) DOMException: Failed to load because no supported source was found

我尝试了来自 here 的以下解决方案:

      var playPromise =  video.play();

      if (playPromise !== undefined) {
                playPromise.then(function () {
                    // Automatic playback started!
                }).catch(function (error) {
                    // Automatic playback failed.
                    $(document).on('click', '#video1', function (e) {
                        var video = $(this).get(0);
                        if (video.paused === false) {
                            video.pause();
                        } else {
                            video.play();
                        }

                        return false;
                    });
                });
       }

但这并没有改变什么。视频区域始终为白色。

最佳答案

我刚刚遇到了一个类似的问题,我只能使用这个 mse example 让我的碎片化 mp4 在 firefox 上播放,但不能在 chrome 上播放.我试图首先提供一个完整的文件而不是通过 websocket 发送它,因为我想确保我的碎片 mp4 格式正确。我发现的问题是,在我的 ffmpeg 命令中,如果我包含 -an 来删除音频,那么我的文件将无法在 chrome 中播放,但仍然可以在 firefox 中运行。不使用音频标志或专门使用 -c:a libfdk_aac 允许我的 mp4 在 chrome 和 firefox 上播放。此外,您应该只需要 -movflags +dash 而不是所有其他 movflags。作为下面我的代码片段的引用,我使用的是来自用 h264 视频编码的 ip 摄像机的 rtsp 提要,因此 -c:v copy

tested on mac, worked on firefox AND safari but NOT chrome:

ffmpeg -i input_source -an -c:v copy -f mp4 -movflags +dash dash.mp4

tested on mac, worked on firefox AND safari AND chrome

ffmpeg -i input_source -c:v copy -f mp4 -movflags +dash dash.mp4

ffmpeg -i input_source -c:a libfdk_aac -c:v copy -f mp4 -movflags +dash dash.mp4

*edit I just found out more information of why the encoding of audio was relevant to playback on chrome. I had the mimetype/codec wrong and chrome was not as forgiving as firefox and safari. var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'; I changed it to var mimeCodec = 'video/mp4; codecs="avc1.42E01E"'; and my mp4 that was encoded without audio played in chrome, as well as the other browsers. Perhaps you have audio but did not include the audio portion of the codec? Or maybe your video codec is not the right one for your video? It is hard to say without seeing your full ffmpeg command that was used to create the file.

*2nd edit. I made a little project to test live streaming mp4 on media source extensions using ffmpeg, nodejs, express, and socket.io. Its a little rough around the edges, but it mostly works.

关于javascript - 碎片化的 MP4 不显示在 Chrome 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47268020/

相关文章:

html - 使用 Bootstrap 时如何将图像设置为容器的背景

html - 如何修复 safari 和 chrome 上的谷歌字体像素化问题

javascript - 计算原点与 x,y,z 坐标之间的 θ 和 ø Angular

javascript - 将每个 <p> 中的文本(div 的子节点)存储在数组中

javascript - 在 React JS 中按姓氏排序从 API 获取的数据

html - 是否有任何 CSS 来对齐框/元素?

css - Div的重叠

xml - XSLT document() 在 WebKit 浏览器中的使用

javascript - Chrome离线版不会使用cache.manifest

javascript - 只检测伪元素的点击事件