2 min read

Python で WebCodecs API を利用できる webcodecs-py を公開しました

ブラウザでは音声や映像のコーデックを利用できる WebCodecs API というのがあります。ただ、当たり前ですが、ブラウザでしか利用できません。

これを Python で使いたい!って思っていたので、 Python で利用できるライブラリを公開しました。

方針

  • scikit-build-corenanobind を利用して完全に時前ビルドにする
  • CMake を利用してマルチプラットフォームにする
  • uv add webcodecs-py で利用できるようにする
  • WebCodecs API にできるだけ準拠する
  • ハードウェアアクセラレーターに対応する
  • numpy.ndarray 前提にする

結果

ほぼほぼ WebCodecs API 準拠で使えるようになりました。違いはコールバック指定を引数にしたくらいです。

import numpy as np

from webcodecs import (
    LatencyMode,
    VideoEncoder,
    VideoEncoderConfig,
    VideoFrame,
    VideoFrameBufferInit,
    VideoPixelFormat,
)

width, height = 320, 240

# エンコーダを作成
encoded_chunks = []


def on_output(chunk):
    encoded_chunks.append(chunk)


def on_error(error):
    raise RuntimeError(f"エンコーダエラー: {error}")


encoder = VideoEncoder(on_output, on_error)
encoder_config: VideoEncoderConfig = {
    "codec": "av01.0.04M.08",
    "width": width,
    "height": height,
    "bitrate": 500_000,
    "framerate": 30.0,
    "latency_mode": LatencyMode.REALTIME,
}
encoder.configure(encoder_config)

# I420 フォーマットのテストフレームを作成
data_size = width * height * 3 // 2
frame_data = np.zeros(data_size, dtype=np.uint8)
init: VideoFrameBufferInit = {
    "format": VideoPixelFormat.I420,
    "coded_width": width,
    "coded_height": height,
    "timestamp": 0,
}
frame = VideoFrame(frame_data, init)

# エンコード
encoder.encode(frame, {"keyFrame": True})
encoder.flush()

print(f"エンコード完了: {len(encoded_chunks)} チャンク, {encoded_chunks[0].byte_length} bytes")

frame.close()
encoder.close()

AV1 をエンコードする仕組み

対応

  • 多くの WebCodec API に対応
  • Opus / FLAC / AAC のエンコードとデコード
  • AV1 / H.264 / H.265 のエンコードとデコード
  • libyuv を利用した VideoPixelFormat 変換対応

何ができるの?

opencv-python 経由のカメラ映像を webcodecs-py で AV1 に変換して mp4-py を利用して MP4 に出力できます。

sounddevice 経由のマイク音声と opencv-python 経由のカメラ映像を webcodecs で Opus / AV1 に変換して libdatachannel-py 経由で WebRTC で配信したりすることができます。

mp4 ファイルの中身をデコードして変換する仕組みなども実装できます。

なんで Python ?

自分が慣れているのが第一ですが、LLM との相性がいいからです。2025 年時点では LLM やるなら Python ほぼ一択です。LLM で音声や映像をとり扱う場合、気軽に利用できるエンコーダーやデコーダーが重要になると思っています。

また C/C++ ベースの Python ライブラリのノウハウは今後も生きると思っています。

MOQT も視野

Media over QUIC Transport (MOQT) では音声や映像を送受信するトンネル部分しか提供しないため、コーデック部分は自力になります。ブラウザでは WebCodecs API を使えばいいですが、別に MOQT はブラウザのためだけの仕組みではありません。

現在時雨堂では Google が公開している QUIC 実装 quiche時前ビルドを提供しており、今後はこの quiche ベースの MOQT を Python 経由で利用できる moqt-py を開発していく予定です。

この時、 webcodecs-py があると、コーデック関連を webcodecs-py に丸投げできるようになります。

公開

blend2d-py + webcodecs-py + libdatachannel-py で WebRTC SFU Sora 経由で配信してブラウザで視聴するデモ映像

0:00
/0:10

想像以上に便利

blend2d-py で 2D アニメーションを作成し、それを webcodecs-py で H.265 (Apple Video Toolbox) で変換し、libdatachannel-py で WebRTC (WHIP) にして、WebRTC SFU Sora へ配信して、ブラウザ (Chrome) で視聴してみるデモ映像です。

雑感

開発期間は 3 ヶ月くらいです。ちまちまと暇を見つけて開発をしていました。3-4 回作り直していますが、かなり良いモノができたと思います。

今後は C++ 実装を整理して性能を出せるようにしたり、Python 3.13 から入った free threading に対応したり、コーデックを増やしたり、WebCodecs API に追従したりしてきたいと思っています。

とにかく使いやすく、性能がでて、落ちない Python ライブラリを目指します。