12
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

WebRTCオッサン問題を超えて。ローカルファイルを自在に操りたい

Posted at

はじめに

前回の記事「WebRTCを試すときにオッサンが映り続ける問題に対処する」は予想外の反響をいただきました。今回はその続編として、ローカルファイルからメディアストリームを作って色々操作してみました。

その後に分かったこと

前回の記事を書いた後にコメントを頂いたり、自分で試したりして、分かったことがあります。

  • CanvasやWeb Audioを使わなくても、videoタグやaudioタグから直接captureStream()できる
    • Firefox 47ではプレフィックス付きの mozCaptureStream()が使える
    • Chromeでも近い将来 captureStream()が使えるようになる
  • 動画系のファイルから、音声だけ取り出して変換することができる
    • audioタグで動画ファイルの音声だけ再生可能
    • Web Audioで音声だけ変換可能
    • ※ わざわざ映像ファイルと音声ファイルを別個に用意する必要はない

前回の記事のようにまどろっこしい処理は不要になりました。嬉しいやら、悔しいやらです。

あえてCanvasが必要なケースを作り出す

負け惜しみとして、あえてCanvasを使ってメディアストリームに変換するサンプルを作って見ました。2つの映像ファイルを用意して、自由に切り替えられるようにしたのがこちらです。

2つの映像の切り替え

demo_fade.gif

切り替えの様子の動画はこちらから(m4v形式、 14MB)
※今回もこちらのNHKクリエイティブライブラリの素材を使わせていただきました。

サンプルページ、ソースコード

Chrome 51, Firefox 47で動かすことができます。

上のアニメーションのように操作する前に、まず映像ファイル×2、音声ファイル×1を指定して、[Start]してからお楽しみください。
demo_start.gif

仕組み

仕組みといっても、ファイルからメディアストリームに変換する方法は前回の記事に記載した内容と同じです。そこで、2つの映像をCanvasで合成する部分について説明します。

スワイプの場合

  • スライダーが0の時はvideo 1の内容を、100の時はvideo 2の内容をCanvasに転写しています
  • あいだの場合は、その割合に応じてvideoの一部を切り出して、 drawImage()で転写します
    • 30ならvideo 1が70%、video 2が30%の比率にしています
swipe30.png
swipe
      let video1Width = Math.round((100- faderValue)/100.0 * localVideo.videoWidth);
      let video2Width = Math.round(faderValue/100.0 * localVideo2.videoWidth);
      let canvasWidth1 = Math.round((100- faderValue)/100.0 * duplicateCanvas.width);
      let canvasWidth2 = Math.round(faderValue/100.0 * duplicateCanvas.width);

      if (canvasWidth1 > 0) {
        ctxDuplicate.drawImage(localVideo, 0, 0, video1Width, localVideo.videoHeight,
          0, 0, canvasWidth1 , duplicateCanvas.height
        );
      }

      if (canvasWidth2 > 0) {
        ctxDuplicate.drawImage(localVideo2, (localVideo2.videoWidth - video2Width), 0, video2Width, localVideo2.videoHeight,
          (duplicateCanvas.width - canvasWidth2), 0, canvasWidth2 , duplicateCanvas.height
        );
      }

ストライプの場合

全体を10個に分割し、その1列ごとにスワイプと同じ処理を行っています。
stripe30.png

ディゾルブの場合

片方を透けさせながらもう片方に切り替えるディゾルブの処理はについては、globalAlphaという指定を使って実現しています。
dissolve30.png

dissolve
      let video1Alpha = (100 - faderValue)/100.0;
      let video2Alpha = (faderValue)/100.0;
      
      ctxDuplicate.globalAlpha = video1Alpha;
      ctxDuplicate.drawImage(localVideo, 0, 0, localVideo.videoWidth, localVideo.videoHeight,
        0, 0, duplicateCanvas.width , duplicateCanvas.height
      );
      
      ctxDuplicate.globalAlpha = video2Alpha;
      ctxDuplicate.drawImage(localVideo2, 0, 0, localVideo2.videoWidth, localVideo2.videoHeight,
        0, 0, duplicateCanvas.width , duplicateCanvas.height
      );

変換したメディアストリームは、RTCPeerConnectionで通信相手に送ることができます。(※ new MediaStream() でオブジェクトを作っているため、現状ではFirefoxではエラーになってしまいます)

おわりに

ローカルファイルをあえてCanvasを使って変換する例をご紹介しました。VJ気分で映像を切り替えながら配信するなんてことが、ブラウザだけでもできるようになりますね。(※既存の動画/音声ファイルを使う場合には、その利用条件は尊重してご利用ください。よろしくお願いします)

HTMLExperts.jpというサイトで「WebRTC入門2016」という連載も書いているので、WebRTCにご興味を持たれた方はそちらもご覧いただけると嬉しいです。

12
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?