Slide 1

Slide 1 text

WebCodecs 実装状況 (2023年6月現在) WebRTC Meetup Tokyo #24 2023.06.23 @massie_g / が こまさし

Slide 2

Slide 2 text

WebCodecs APIと ● VideoやAudioをエンコード、デコードするAPI ● 仕様 ○ WebCodecs W3C Working Draft, 11 May 2023 ○ https://www.w3.org/TR/webcodecs/ ● 関連する仕様 ○ MediaStreamTrack Insertable Media Processing using Streams ■ Editor’s Draft, 20 October 2022 ● https://w3c.github.io/mediacapture-transform/ ■ Unofficial Proposal Draft, 26 November 2021 ● https://alvestrand.github.io/mediacapture-transform/chrome-96.html

Slide 3

Slide 3 text

https://caniuse.com/webcodecs ● Chrome 114 / Edge 114 … Video, Audio サポート ● Safari TP171 … Video みサポート, オプション指定 ● Firefox … 未対応

Slide 4

Slide 4 text

Video

Slide 5

Slide 5 text

VideoFrame VideoEncoder EncodedVideoChunk EncodedVideoChunk EncodedVideoChunk VideoDecoder VideoFrame VideoEncoder / VideoDecoder

Slide 6

Slide 6 text

VideoFrame VideoEncoder EncodedVideoChunk EncodedVideoChunk EncodedVideoChunk VideoDecoder VideoFrame VideoFrameを作る/使う ImageBitmap OffscreenCanvas VideoFrame コンストラクタ new VideoFrame() drawImage()

Slide 7

Slide 7 text

VideoFrameを作る const frame = new VideoFrame(element, { timestamp: timestamp_in_micro_second, // タイムスタンプをμ秒で指定 duration: duration_in_micro_second, // フレーム 長さをμ秒で指定 }); // do something with frame // release frame.close(); 属性 ● readonly attribute VideoPixelFormat? format; ● readonly attribute unsigned long codedWidth; ● readonly attribute unsigned long codedHeight; ● readonly attribute DOMRectReadOnly? codedRect; ● readonly attribute DOMRectReadOnly? visibleRect; ● readonly attribute unsigned long displayWidth; ● readonly attribute unsigned long displayHeight; ● readonly attribute unsigned long long? duration; // μs ● readonly attribute long long timestamp; // μs ● readonly attribute VideoColorSpace colorSpace;

Slide 8

Slide 8 text

VideoFrame フォーマット ● 元にした要素により、フォーマットが異なる ● ブラウザによっても、フォーマットが異なる 元 要素
 Chrome 114
 / Canary 116
 (Win10, M1 Mac)
 afari P 171
 (M1 Mac)
 img(jpeg)
 BG X
 GBA
 canvas
 GBA
 GBA
 video(mp4)
 NV12
 I420
 video(camera)
 I420
 I420
 ● BGRX ○ Blue, Green, Red, ○ X:透明度 … 255で透明 ● RGBA ○ Red, Green, Blue ○ A:αチャンネル … 255で不透明 ● YUV420 (NV12, I420) ○ 画像/映像 情報量を抑える形式 ■ https://qiita.com/Yossy_Hal/items/8e0b9676698 ba552c210 ○ Y(輝度), U(青色式差), V(赤色式差) ■ Y そ まま ■ U, V 縦横半分に間引く ○ U, V 並べ方 違いでNV12とI420がある

Slide 9

Slide 9 text

VideoFrameを使う: Canvasに描画 const ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, width, height); ctx.drawImage(videoframe, 0, 0);

Slide 10

Slide 10 text

Encode → Decode実験 (1) Encoder const encoder = new VideoEncoder({ output: (chunk) => { // エンコード成功時 処理 }, error: (err) => { /* エラー時 処理 */ } }); await encoder.configure({ codec: CODEC, // コーデック 指定 width: WIDTH, // 幅 指定 height: HEIGHT, // 高さ 指定 framerate: 10 // フレームレート 指定 }); // フレーム取得 const frame = new VideoFrame(element, { timestamp: timestamp_in_micro_second, duration: duration_in_micro_second }); // エンコード (成功すると、output に指定した関数が呼 れ る) encoder.encode(frame, { keyFrame : true}); // true: キーフレーム、false: 差分フレーム frame.close(); // フレームを解放

Slide 11

Slide 11 text

Encode → Decode実験 (2) Decoder const decoder = new VideoDecoder({ output: (frame) => { // デコード成功時 処理 frame.close(); //フレームを解放 }, error: (err) => { /* エラー時 処理 */ } }); await decoder.configure({ codec: CODEC }); // デコード (成功すると、output に指定した関数が呼 れる) decoder.decode(chunk); // chunk エンコード済み データ

Slide 12

Slide 12 text

Encode → Decode実験(img, mp4, カメラ映像、全てkeyframe) コーデック Chrome 114 / Canary 116 (Win10, M1 Mac) Safari TP 171 (M1 Mac) デコード結果 デコード後 フォーマット デコード結果 デコード後 フォーマット VP8 〇 2フレーム目 デコードで表示 (outputが呼 れる) I420 〇(img, video:カメラ映像) 1フレーム目 デコードで表示 ✕(video:mp4) 緑色や崩れた描画 I420 VP9 profile0 〇 1フレーム目 デコードで表示 NV12 〇(img, video:カメラ映像) 1フレーム目 デコードで表示 ✕(video:mp4) 緑色や崩れた描画 I420 VP9 profile2 〇 1フレーム目 デコードで表示 null ✕ エラー: Not supported ✕ AV1 〇 4フレーム目 デコードで表示 I420 ✕ NotSupportedError: VPx encoding initialization failed with error -1 ✕ H.264 〇 2フレーム目 デコードで表示 NV12 〇 1フレーム目 デコードで表示 I420

Slide 13

Slide 13 text

参考: Encoder/Decoder 初期化オプション コーデック encoder.configure() オプション例 decoder.configure() オプション例 VP8 codec : "vp8" codec : "vp8" VP9 profile0 codec: "vp09.00.10.08" codec: "vp09.00.10.08" VP9 profile2 codec: "vp09.02.10.10" codec: "vp09.02.10.10" AV1 codec: "av01.0.01M.08" codec: "av01.0.01M.08" H.264 codec: "avc1.42001E", avc: { format: "annexb" } codec: "avc1.42001E"

Slide 14

Slide 14 text

Audio

Slide 15

Slide 15 text

AudioEncoder EncodedAudioChunk EncodedAudioChunk AudioDecoder AudioEncoder / AudioDecoder AudioData AudioData AudioData AudioData AudioData AudioData AudioData AudioData AudioData AudioData Chromeで 20ms 長さで分割 EncodedAudioChunk EncodedAudioChunk EncodedAudioChunk EncodedAudioChunk EncodedAudioChunk EncodedAudioChunk Chromeで 48k sample/sec, 20ms 長さ Chromeで 3k~768k sample/sec 長さ 自由

Slide 16

Slide 16 text

AudioData const audioData = new AudioData({ format: format, // "u8", "s16", "s32", "f32", (※"f32" み確認) // "u8-planar", "s16-planar", "s32-planar", "f32-planar" sampleRate: sampleRate, // Chromeで 3,000 ~ 768,000 numberOfFrames: frames, // 何個分 サンプルを持っているか numberOfChannels: channels, // 1:モノラル or 2:ステレオ (※1: み確認) timestamp: timestamp, // μ秒で指定 data: data }); ※WebAudio AudioBufferと 異なる。そ ままで 再生できない

Slide 17

Slide 17 text

AudioEncoder encoder = new AudioEncoder({ output: (chunk) => {   // エンコード成功時 処理 }, error: (err) => { /* エラー時 処理 */ } }); await encoder.configure({ codec: CODEC, numberOfChannels: 1 sampleRate: SAMPLE_RATE, }); 仕様上 CODEC ● Audio Codecs https://w3c.github.io/webcodecs/codec_registry.htm l#audio-codec-registry ● "flac" ... Flac ● "mp3" ... MP3 ● "mp4a.*" ... AAC ● "opus" ... OPUS ● "vorbis" ... Vorbis ● "ulaw" ... u-law PCM ● "alaw" ... A-law PCM ● "pcm-*" ... Linear PCM → 現状Chrome OPUS みサポート

Slide 18

Slide 18 text

AudioDecoder decoder = new AudioDecoder({ output: async (audioData) => { // デコード成功時 処理 audioData.close(); }, error: (err) => { /* エラー時 処理 */ } }) await decoder.configure({ codec: CODEC, numberOfChannels: 1, sampleRate: SAMPLE_RATE, }); // エンコード encoder.encode(audioData); // デコード decoder.decode(chunk);

Slide 19

Slide 19 text

MediaStreamTrack Insertable Media Processing using Streams Processor / Generator

Slide 20

Slide 20 text

Processor / Generator MediaStream MediaStreamTrack (video) MediaStreamTrack (audio) MediaStreamTrack Processor MediaStreamTrack Processor VideoFrame AudioData AudioData AudioData MediaStreamTrack Generator MediaStreamTrack Generator MediaStreamTrack (video) MediaStreamTrack (audio) MediaStream Encoder ↓ Decoder VideoFrame AudioData AudioData AudioData

Slide 21

Slide 21 text

MediaStream/MediaStreamTrackと 組合せ MediaStreamTrack Insertable Media Processing using Streams Unofficial Proposal Draft, 26 November 2021 Editor’s Draft, 20 October 2022 Chrome 114 (Unofficial Proposal) Safari TP171 未対応 MediaStreamTrack → VideoFrame MediaStreamTrackPr ocessor MediaStreamTrack Processor MediaStreamTrack Processor 未対応 VideoFrame → MediaStreamTrack MediaStreamTrackG enerator VideoTrackGenera tor MediaStreamTrack Generator 未対応 MediaStreamTrack → AudioData MediaStreamTrackPr ocessor MediaStreamTrack Processor MediaStreamTrack Processor 未対応 AudioData → MediaStreamTrack MediaStreamTrackG enerator なし MediaStreamTrack Generator 未対応

Slide 22

Slide 22 text

まとめ ● WebCodecs ○ Chrome かなり実装もこなれてきた ■ Chrome限定なら、使える場面もありそう ○ Safari まだまだ、Audio無し ■ Safariで使うなら、H.264が無難 ● MediaStreamTrack Insertable Media Processing using Streams ○ 仕様がまた整理されていない、使うに まだ早い ■ Chromeで 実験 、もう始められる 個人 見解 ● WebCodecsが普及する まだまだ先(5年以上) ● し らく WebRTCで行く が吉