碎片化的MP4未显示在Chrome

时间:2017-11-13 15:36:23

标签: javascript html5 google-chrome video video-streaming

但在Firefox中运行良好。

Google Chrome版本:61.0.3163.100(官方版本)(64位)

Mozilla Firefox版本:56.0.2(64位)

我的视频片段化MP4通过WebSocket流式传输到客户端html页面,然后将其提取到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()电话。这实际上是应用程序启动时抛出错误的唯一地方:

  

未捕获(承诺)DOMException:无法加载,因为没有   找到支持的来源

我尝试了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;
                    });
                });
       }

但它没有改变。视频区域始终为白色。

3 个答案:

答案 0 :(得分:1)

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

  

在mac上测试过,在firefox和safari上工作但不是chrome:

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

  

在mac上测试过,在firefox和safari上进行了操作和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

  

*编辑我刚刚找到了有关音频编码与Chrome播放相关的更多信息。我的mimetype / codec错了,chrome并不像firefox和safari那样宽容。   var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';   我将其更改为var mimeCodec = 'video/mp4; codecs="avc1.42E01E"';,我的mp4编码无音频以chrome格式播放,以及其他浏览器。也许你有音频但不包括编解码器的音频部分?或者您的视频编解码器可能不适合您的视频?如果没有看到用于创建文件的完整ffmpeg命令,很难说。

     

*第二次编辑。我使用ffmpeg,nodejs,express和socket.io在媒体源扩展上测试了实时流式传输mp4 little project。   它的边缘有点粗糙,但它大部分都有效。

答案 1 :(得分:0)

这在Firefox和Chrome上对我有效:

ffmpeg -i input.any \
  -f mp4 \
  -movflags faststart+separate_moof+empty_moov+default_base_moof \
  -acodec aac -b:a 256000 \
  -frag_duration 500K \
   output.mp4

还可与Meadia Source Extension API中的SourceBuffer一起使用。您在这里寻找的Mime-Type是audio/mp4; codecs="mp4a.40.2"

但是在这一点上,我不确定如何在该文件中进行查找(如果可能的话),例如如果您不想将整个文件发送到客户端,而是从特定的时间戳开始,然后直接跳至[moof][mdata]对以开始加载。

答案 2 :(得分:0)

Chrome 不喜欢视频没有音频。

如果您使用 m4s 片段(本质上是碎片化 mp4 的块)生成 HLS 播放列表,那么您还需要确保有音频,否则它根本不会播放。

这个应该适用于所有浏览器:

ffmpeg -y -i SOURCE.mp4 -f lavfi -i aevalsrc=0 -af apad -shortest -c:v copy -movflags empty_moov+default_base_moof+frag_keyframe+omit_tfhd_offset -write_tmcd off FRAGMENTED_WITH_PADDED.mp4