MediaRecorderをMediaSourceとして使用する方法


8

WebRTCの学習の練習として、ローカルWebカメラを表示し、Webカメラの遅延再生を並べて表示しようとしています。これを達成するために、記録されたblobをBufferSourceに渡し、対応するMediaSourceをビデオ要素のソースとして使用しようとしています。

// the ondataavailable callback for the MediaRecorder
async function handleDataAvailable(event) {
  // console.log("handleDataAvailable", event);
  if (event.data && event.data.size > 0) {
    recordedBlobs.push(event.data);
  }

  if (recordedBlobs.length > 5) {
    if (recordedBlobs.length === 5)
      console.log("buffered enough for delayed playback");
    if (!updatingBuffer) {
      updatingBuffer = true;
      const bufferedBlob = recordedBlobs.shift();
      const bufferedAsArrayBuffer = await bufferedBlob.arrayBuffer();
      if (!sourceBuffer.updating) {
        console.log("appending to buffer");
        sourceBuffer.appendBuffer(bufferedAsArrayBuffer);
      } else {
        console.warn("Buffer still updating... ");
        recordedBlobs.unshift(bufferedBlob);
      }
    }
  }
}
// connecting the media source to the video element
recordedVideo.src = null;
recordedVideo.srcObject = null;
recordedVideo.src = window.URL.createObjectURL(mediaSource);
recordedVideo.controls = true;
try {
  await recordedVideo.play();
} catch (e) {
  console.error(`Play failed: ${e}`);
}

すべてのコード:https : //jsfiddle.net/43rm7258/1/

Chromium 78でこれを実行すると、video要素の要素NotSupportedError: Failed to load because no supported source was found.からを取得しplayます。

私は自分が間違っていることや、この時点でどのように進めるかについての手がかりはありません。

これは似たようなものですが、助けにはなりません:MediaSourceがランダムにビデオを停止します

この例は私の出発点でした:https : //webrtc.github.io/samples/src/content/getusermedia/record/

回答:


9

要約すれば

FirefoxとChromeで動作させるのは簡単です。オーディオコーデックをコーデックリストに追加するだけです。 video/webm;codecs=opus,vp8

Safariで機能させるには、かなり複雑です。MediaRecorderは、開発者向けオプションの下で手動で有効にする必要がある「実験的」機能です。有効にすると、SafariにはisTypeSupportedメソッドがないため、それを処理する必要があります。最後に、MediaRecorderから何をリクエストしても、Safariは常に MP4ファイルを渡します。これは、WEBMのようにストリーミングすることはできません。つまり、ビデオコンテナーの形式をその場で変換するには、JavaScriptでトランスマックスを実行する必要があります。

Chromeが動作すればAndroidは動作するはずです

iOSはMedia Source Extensionsをサポートしていないため、iOSではSourceBuffer定義されておらず、ソリューション全体が機能しません

元の投稿

あなたが投稿したJSFiddleを見ると、始める前の簡単な修正が1つあります。

  • errorMsgElement定義されていない変数を参照しています。<div>ページに適切なIDを追加し、const errorMsgElement = document.querySelector(...)それをキャプチャするための行を作成する必要があります

Media Source ExtensionsとMediaRecorderを使用するときに注意すべき点は、サポートがブラウザーごとに大きく異なることです。これはHTML5仕様の「標準化された」部分ですが、プラットフォーム間であまり一貫性がありません。私の経験では、MediaRecorderをFirefoxで動作させるのにそれほど労力はかかりません。Chromeで動作させることは少し難しく、Safariで動作させることはほぼ不可能であり、iOSで動作させることは文字通り不可能ですあなたができる何か。

ブラウザごとにこれを実行してデバッグし、私の手順を記録して、メディアの問題をデバッグするときに使用できるツールの一部を理解できるようにしました

Firefox

FirefoxでJSFiddleをチェックアウトすると、コンソールに次のエラーが表示されました。

NotSupportedError:オーディオトラックを記録できません:video / webm; codecs = vp8はサポートされていないコーデックを示します

VP8 / VP9はGoogleによる大きなプッシュであり、Firefoxでは機能しない可能性があることを思い出したので、コードを少し調整しました。への, options)呼び出しからパラメータを削除しましたnew MediaRecorder()。これはおそらく、すべてのブラウザで異なる出力を取得します(それは、少なくともする必要がありますので、それは、望んでいるものは何でもコーデックを使用するブラウザに指示作品すべてのブラウザで)

これはFirefoxで機能したため、Chromeをチェックアウトしました。

クロム

今回は新しいエラーが発生しました:

(インデックス):409キャッチされていません(約束どおり)DOMException: 'SourceBuffer'で 'appendBuffer'を実行できませんでした:このSourceBufferは親メディアソースから削除されました。MediaRecorder.handleDataAvailable(https://fiddle.jshell.net/43rm7258/1/show/:409:22

だから私は私のブラウザーでchrome:// media-internals /に行き、これを見ました:

オーディオストリームコーデックのopusがSourceBufferコーデックと一致しません。

コードでは、ビデオコーデック(VP9またはVP8)を指定していますが、オーディオコーデックは指定していません。そのため、MediaRecorderは、ブラウザーに必要なオーディオコーデックを選択させます。デフォルトでは、ChromeのMediaRecorderはオーディオコーデックとして「opus」を選択しているように見えますが、ChromeのSourceBufferはデフォルトで別のものを選択します。これは簡単に修正されました。次のoptions.mimeTypeように設定した2行を更新しました。

  • options = { mimeType: "video/webm;codecs=opus, vp9" };
  • options = { mimeType: "video/webm;codecs=opus, vp8" };

optionsMediaRecorderとSourceBufferの宣言に同じオブジェクトを使用するため、オーディオコーデックをリストに追加すると、SourceBufferが有効なオーディオコーデックで宣言され、ビデオが再生されます。

適切な対策として、Firefoxで新しいコード(オーディオコーデックを使用)をテストしました。これはうまくいった!したがって、optionsリストにオーディオコーデックを追加するだけで(そしてMediaRecorderを宣言するためにパラメーターにそれを残すことで)、2対2 になります。

VP8とopusはFirefoxで動作するように見えますが、デフォルトではありません(Chromeとは異なり、MediaRecorderとSourceBufferのデフォルトは同じであるため、optionsパラメーターを完全に削除すると機能します)

サファリ

今回は、処理できない可能性のあるエラーが発生しました。

未処理のPromise拒否:ReferenceError:変数が見つかりません:MediaRecorder

私が最初に行ったのは、この記事を取り上げたGoogle "Safari MediaRecorder" でした。やってみようかなと思って見てみました。案の定:

Safariのプロパティ

これをクリックしてMediaRecorderを有効にすると、コンソールで次のようになりました。

未処理のPromise拒否:TypeError:MediaRecorder.isTypeSupportedは関数ではありません。(「MediaRecorder.isTypeSupported(options.mimeType)」では、「MediaRecorder.isTypeSupported」は未定義です)

したがって、SafariにはisTypeSupportedメソッドがありません。心配する必要はありません。「このメソッドが存在しない場合は、Safariであると想定し、それに応じてタイプを設定します」

  if (MediaRecorder.isTypeSupported) {
    options = { mimeType: "video/webm;codecs=vp9" };
    if (!MediaRecorder.isTypeSupported(options.mimeType)) {
      console.error(`${options.mimeType} is not Supported`);
      errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
      options = { mimeType: "video/webm;codecs=vp8" };
      if (!MediaRecorder.isTypeSupported(options.mimeType)) {
        console.error(`${options.mimeType} is not Supported`);
        errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
        options = { mimeType: "video/webm" };
        if (!MediaRecorder.isTypeSupported(options.mimeType)) {
          console.error(`${options.mimeType} is not Supported`);
          errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
          options = { mimeType: "" };
        }
      }
    }
  } else {
    options = { mimeType: "" };
  }

今、私はSafariがサポートするmimeTypeを見つける必要がありました。軽いグーグルはH.264がサポートされていることを示唆しているので、試してみました:

options = { mimeType: "video/webm;codecs=h264" };

これは私MediaRecorder startedに成功しましたがaddSourceBuffer、新しいエラーで行で失敗しました:

NotSupportedError:この操作はサポートされていません。

私はこれをSafariで機能させる方法を試し、診断するつもりですが、今のところ私は少なくともFirefoxとChromeに対処しています

アップデート1

私はサファリに取り組み続けました。残念なことに、Safariにはメディアの内部を深く掘り下げるためのChromeとFirefoxのツールが欠けているため、多くの推測が行われます。

以前にを呼び出そうとすると、「操作はサポートされていません」というエラーが発生することがわかりましたaddSourceBuffer。そこで、さまざまな状況でこのメソッドだけを呼び出して呼び出すための1回限りのページを作成しました。

  • playビデオで呼び出される前にソースバッファーを追加する
  • メディアソースがビデオ要素にアタッチされる前にソースバッファーを追加する
  • たぶん、異なるコーデックでソースバッファを追加します

問題はまだコーデックであり、許可されていない「操作」に関するエラーメッセージは少し誤解を招くことがわかりました。許可されなかったパラメーターです。MediaRecorderでは「h264」を指定するだけで機能しましたが、SourceBufferではコーデックパラメータを渡す必要がありました。

最初に試したのは、MDNサンプルページに移動し、そこで使用したコーデックをコピーすること'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'でした。これにより、同じ「許可されていない操作」エラーが発生しました。これらのコーデックのパラメータの意味を掘り下げる(一体何んのように42E01Eしても意味?)。私はもっ​​と良い答えがあればいいのに、グーグルしながら、Safariでの使用について言及したこのStackOverflowの投稿を偶然見つけました'video/mp4; codecs="avc1.64000d,mp4a.40.2"'。私はそれを試してみましたが、コンソールエラーはなくなりました!

コンソールエラーはなくなりましたが、まだビデオが表示されません。ですから、やるべきことはまだあります。

アップデート2

Safariのデバッガーでさらに調査(複数のブレークポイントを配置し、プロセスの各ステップで変数を検査)したところhandleDataAvailable、Safariで呼び出されたことがないことがわかりました。FirefoxとChromeではmediaRecorder.start(100)、仕様に従ってondatavailable100ミリ秒ごとに正しく呼び出されるように見えますが、Safariはパラメーターを無視し、すべてを1つの大きなBlobにバッファーします。mediaRecorder.stop()手動で呼び出すondataavailableと、その時点までに記録されていたすべてのものが呼び出されます

を使用setIntervalmediaRecorder.requestData()て100ミリ秒ごとに呼び出しを試みましたrequestDataが、Safariで定義されていませんでした(どのようisTypeSupportedに定義されなかったかのように)。これは私を少し困らせました。

次に、MediaRecorderオブジェクト全体をクリーンアップし、100ミリ秒ごとに新しいオブジェクトを作成しようとしましたが、これにより行にエラーが発生しましたawait bufferedBlob.arrayBuffer()。それが失敗した理由を私はまだ調査しています

アップデート3

MP4形式について覚えていることの1つは、コンテンツを再生するには「moov」アトムが必要であることです。これが、MP4ファイルの中央部分をダウンロードして再生できない理由です。WHOLEファイルをダウンロードする必要があります。それで、MP4を選択したのが定期的な更新を取得しなかった理由なのかと思いました。

video/mp4いくつかの異なる値に変更しようとすると、さまざまな結果が得られました。

  • video/webm -操作はサポートされていません
  • video/x-m4v-MP4のように動作し、.stop()が呼び出されたときにのみデータを取得しました
  • video/3gpp -MP4のように動作
  • video/flv -操作はサポートされていません
  • video/mpeg -MP4のように動作

MP4のように動作するすべてのものから、実際に渡されているデータを検査するようになりましたhandleDataAvailable。それは私がこれに気付いたときです:

ここに画像の説明を入力してください

どんなに何を私はビデオフォーマットのために選択し、Safariはいつも私にMP4を与えていました!

突然、サファリがこんなに悪夢だったのはなぜか、なぜそれを精神的に「とんでもないほど不可能」に分類したのかを思い出しました。複数のMP4をつなぎ合わせるには、JavaScriptトランスマルチプレクサーが必要です。

それは私が覚えていたときです、それはまさに以前にやったことです。MediaRecorderとSourceBufferを1年ほど前に使用して、JavaScript RTMPプレーヤーを作成してみました。プレーヤーが完成したら、MediaRecorderを使用してリングバッファーを1秒のビデオBLOBのメモリに保持することで、DVR(既にストリーミングされたビデオの一部に戻る)のサポートを追加したいと思いました。Safariでは、これらのビデオblobをMP4からISO-BMFFに変換するようにコード化したトランスマクサーを介して実行し、それらを連結できるようにしました。

コードをあなたと共有できればいいのですが、すべてコードは私の古い雇用主が所有しています。そのため、この時点では解決策はありません。誰かがemscriptenを使用してFFMPEGをJavaScriptにコンパイルする問題を経験したことを知っているので、あなたはそれを利用できるかもしれません。


うわー!本当にありがとうございました!あなたがこれに費やした努力に本当に驚いています。私はあなたの調査結果を検討し、私が物事を機能させることができるかどうかを確認します。
アンドレ

1
あなたのポインタで、私は確かにそれをChromeで動かしています、私は解決策に近づいていましたが、それを続行する方法の手がかりがありませんでした。追跡するために実行した手順を説明していただきありがとうございます。ありがとうございました。あなたの答えは本当に役に立ち、私は多くのことを学びました。
アンドレ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.