web-dev-qa-db-ja.com

MediaSourceエラー:このSourceBufferは親メディアソースから削除されました

Chromeで利用できる新しいMediaSource APIを実験しています。

WebSocketからビデオメディアソースにその場でバイナリデータを追加しようとしています。

https://html5-demos.appspot.com/static/media-source.html の例から始めて、私のコードは現在:

_var websocket = new WebSocket('ws://localhost:8080');
websocket.binaryType = 'arraybuffer';

var mediaSource = new MediaSource();
var buffer;
var queue = [];

var video = $('.video')[0];
video.src = window.URL.createObjectURL(mediaSource);

mediaSource.addEventListener('sourceopen', function(e) {
  video.play();

  buffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.64001E"');

  buffer.addEventListener('updatestart', function(e) { console.log('updatestart: ' + mediaSource.readyState); });
  buffer.addEventListener('update', function(e) { console.log('update: ' + mediaSource.readyState); });
  buffer.addEventListener('updateend', function(e) { console.log('updateend: ' + mediaSource.readyState); });
  buffer.addEventListener('error', function(e) { console.log('error: ' + mediaSource.readyState); });
  buffer.addEventListener('abort', function(e) { console.log('abort: ' + mediaSource.readyState); });

  buffer.addEventListener('update', function() { // Note: Have tried 'updateend'
    if (queue.length > 0 && !buffer.updating) {
      buffer.appendBuffer(queue.shift());
    }
  });
}, false);

mediaSource.addEventListener('sourceopen', function(e) { console.log('sourceopen: ' + mediaSource.readyState); });
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); });

websocket.addEventListener('message', function(e) {
  if (typeof e.data !== 'string') {
    if (buffer.updating || queue.length > 0) {
      queue.Push(e.data);
    } else {
      buffer.appendBuffer(e.data);
    }
  }
}, false);
_

常にエラーメッセージが表示されます:1回の追加後に_InvalidStateError: Failed to execute 'appendBuffer' on 'SourceBuffer': This SourceBuffer has been removed from the parent media source._。 MediaSourceはbuffer.appendData()の呼び出し直後に閉じているようです。

これをエレガントに行う方法はありますか?

注:chrome:// media-internals /は有用な情報を返しません。

27
Chris Nolet

結局のところ、問題はWebソケットを介してh264ビデオを送信していたことでした。 MediaSource APIは、現在(Chrome 35)で)キーフレーム化されたセグメントを持つMPEG-DASHおよびVP8のみをサポートしています。

さらに、VP8を試してみると、順不同でいくつかのフレームを追加していることがわかりました。

  • _websocket.onmessage_にif (buffer.updating || queue.length > 0)を追加する必要がありました。
  • if (queue.length > 0 && !buffer.updating)buffer.addEventListener('update', ...)を追加することも必要でした。

注:ここで説明した編集を質問のコードに適用したため、質問のコードの唯一の問題は、コーデックが間違っていることです

8
Chris Nolet

SourceBufferコーデックに関しては、Chromeは信じられないほどうるさいです。さらに悪いことに、OPの場合と同様に、役に立たない誤解を招くエラーメッセージが返されます。

MediaSourceはbuffer.appendData()の呼び出し直後に閉じているようです

それはまさにその通りです:Chromeは、どういうわけか正確に好みに適合しないため、ビデオに満足していませんそしてソースバッファを予告なしに単に閉じます

探すべき可能な解決策:

  1. ffmpeg を使用してMP4ファイルをトランスコードし、説明 here (headlineFragmenting)を説明します。
  2. ここで および ここで と説明されている正確なMP4コーデックを見つけるには、 mp4v2 のmp4fileを使用します。
  3. オーディオがない場合は、オーディオコーデックの部分を省略します。 'video/mp4; codecs="avc1.64001F"' の代わりに 'video/mp4; codecs="avc1.64001F, mp4a.40.2"'
0
The Conspiracy