We will not respond to PRs or issues that have not been discussed on Discord. Also, Discord is only available in Japanese.
Please read https://github.com/shiguredo/oss/blob/master/README.en.md before use.
利用前に https://github.com/shiguredo/oss をお読みください。
mp4-rust の Python バインディングです。 MP4 コンテナフォーマットの読み書きをサポートしています。
- macOS 26 arm64
- macOS 15 arm64
- Ubuntu 24.04 x86_64 (manylinux2014 wheel は glibc 2.17+ 対応)
- Ubuntu 24.04 arm64 (manylinux2014 wheel は glibc 2.17+ 対応)
- Windows Server 2025 x86_64
- Windows 11 x86_64
- 3.14 (abi3 wheel: 3.12/3.13/3.14 共通)
- 3.14t (Free-Threading, 専用 wheel)
- 3.13 (abi3 wheel)
- 3.12 (abi3 wheel)
uv add mp4-pyMp4FileDemuxer/Mp4FileMuxer- ビデオ/オーディオ/字幕トラックの読み書きをサポート
- Opus / AAC / FLAC 音声コーデック対応
- VP8 / VP9 / AV1 / H.264 / H.265 映像コーデック対応
- STPP (XML 字幕) / WVTT (WebVTT 字幕) / TX3G (3GPP タイムドテキスト) 対応
- Python Free Threading 対応
- 破損 MP4 データはパースエラーを
RuntimeErrorとして報告する。ftyp パース成功後のショートリードはMp4Exception(=RuntimeErrorのサブクラス) として報告し、ftyp が読みきれない場合のショートリードはエラーなく「トラック 0 本の正常終了」になる - エラー発生後のデマクサーは
tracksが空リスト、以後の反復はStopIterationで終わる - 非対応: fragmented MP4 (fMP4)。
Mp4FileDemuxerは fMP4 を読み取れず、stbl が空の典型的な init segment ではエラーなく「サンプル 0 個の正常終了」になる
import io
from mp4 import Mp4FileDemuxer
# ファイルパスから demuxer を作成
with Mp4FileDemuxer("input.mp4") as demuxer:
# サンプルを走査して処理
for sample in demuxer:
print(f"Sample: {sample.timestamp_seconds}s, keyframe={sample.keyframe}")
print(f"Data size: {len(sample.data)} bytes")
# バイナリストリームから demuxer を作成
with open("input.mp4", "rb") as fp:
demuxer = Mp4FileDemuxer(fp)
for sample in demuxer:
# サンプルを処理...
passimport io
from mp4 import (
Mp4FileMuxer,
Mp4MuxSample,
Mp4SampleEntryVp08,
)
# ファイルにマルチプレックス
with Mp4FileMuxer("output.mp4") as muxer:
# VP8 ビデオサンプルエントリーを作成
video_entry = Mp4SampleEntryVp08(
width=1920,
height=1080,
)
# フレームを追加
for i in range(30):
is_keyframe = (i % 10) == 0 # 10フレームごとにキーフレーム
# ビデオデータ(実際のエンコード済みデータに置き換えてください)
video_data = b'\x00' * 1000
# サンプルを作成して追加
sample = Mp4MuxSample(
track_kind="video",
sample_entry=video_entry,
keyframe=is_keyframe,
timescale=30,
duration=1,
data=video_data,
)
muxer.append_sample(sample)
# finalize() を呼んでファイルを完成させる(自動的に呼ばれるが明示的に呼ぶこともできます)
# バイナリストリームにマルチプレックス
with open("output.mp4", "wb") as fp:
with Mp4FileMuxer(fp) as muxer:
# マルチプレックス処理...
passappend_sample() は失敗時に、書き込んだバイトをストリームから巻き戻します。
- seekable なストリームでは巻き戻しに成功するため、入力 (timescale や sample_entry など) を補正して
append_sample()を retry できます - 非 seekable なストリーム (実パイプなど) や巻き戻しに失敗した場合は、Muxer が使用不能になり、以後の動作は保証されません。例外は
RuntimeErrorになり、メッセージに案内と元のエラーが含まれます - 使用不能になった Muxer は
close()を呼ばずに破棄してください。close()は finalize を実行して破損ファイルを書き出すためです with構文では例外発生時も__exit__がclose()を実行してしまうため、非 seekable なストリームではwith構文を使わず、失敗時の破棄を考慮した使用方法を取ってください
from mp4 import Mp4FileDemuxer
with Mp4FileDemuxer("input.mp4") as demuxer:
for track in demuxer.tracks:
print(f"Track ID: {track.track_id}")
print(f"Kind: {track.kind}") # 'video' / 'audio' / 'subtitle'
print(f"Duration: {track.duration_seconds:.2f}s")Warning
- 現在は基本的な読み書き機能をサポートしています
- マルチプレックス時は最初のサンプルで
sample_entryを必須で指定してください - 同じトラック内で同じコーデック設定が続く場合、
sample_entryにNoneを指定できます
examples/demux.py: MP4 ファイルをデマルチプレックスしてトラックとサンプル情報を表示examples/remux.py: MP4 ファイルをリマルチプレックス(読み込んで別ファイルに書き込む)
実行例:
uv run python examples/demux.py input.mp4
uv run python examples/remux.py input.mp4 output.mp4# maturin をインストール
uv pip install maturin
# 開発ビルド (editable install)
maturin develop --release
# wheel を生成
maturin build --release --out wheelhouse --generate-stubs
# テスト
uv pip install pytest pytest-timeout hypothesis
uv run pytest tests/ --timeout=30Rust 側は crates.io の shiguredo_mp4
を通常の cargo 依存として参照している (Cargo.toml を参照)。
Apache License 2.0
Copyright 2024-2026, Takeru Ohta (Original Author)
Copyright 2024-2026, Shiguredo Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License 2.0
Copyright 2025 Takeru Ohta (Original Author)
Copyright 2025 Shiguredo Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.