index

2006年 12月
          1 2 3
  4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
  25 26 27 28 29 30 31
2007年 1月
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
2007年 2月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28        

アレ

H.264 の avi を mp4 に(on FreeBSD server   ▽20070103b #コンピュータ #動画圧縮

さて avi の問題点も把握したところで, やっと mkvtoolnix に 「allow_avc_in_vfw_mode」なんてモードがある理由も把握できたような気がする昨今. 「1フレームに 2個押し込めつつヌルのフレームを挿入」とか 「必ず 1フレームずつずれる」とか, ちょっと齧っただけでもとてつもなく美しくない策を弄するしかないあたり, きっと avi フォーマットってのは世界の各地でこよなく憎まれていることであろう.

ただ上記の mkvtoolnix の出力によると, 「VFW モードの AVC を Matroska コンテナに押し込めるのは未定義. いったん MP4Box で洗ってから native モードで入れなおしな」と出るので, まぁこちらとしては初めから mp4 にしようとしてるわけだが, するってーと MP4Box ってのは「きれいな」H.264 ファイルにして格納してくれるのかしらね?

早速 MP4Box を使ってみるわけだが, まぁ Windows 上だと GUI とかもちろん存在するわけで, YAMB という MP4Box のフロントエンドがしっかりあるわけですな.

ちなみに以下のような手順になる.

  1. PV3 で録画.→ .dv (EARTH DV 形式)
  2. TMPGEnc4XP で CM カット& x264 出力 → .avi (H.264/VFW + MP3)
  3. MP4Box で raw video と raw audio を extract → .h264 + .mp3
  4. MP3 を AAC に変換 → .aac
  5. MP4Box で .h264 + .aac を .mp4 にエンコード → .mp4

うわぁ面倒くさいw

こういう面倒なのはバッチファイルにしてコマンドラインでやってしまうに限るわけだが, うちの環境の場合これらを行なう場所がネットワークドライブ上なので, 数 GB のファイルをいちいちネットワーク横断させないといけなくて, 大変に遅くなってしまう. そこで,どうせならこれらの作業すべてファイルサーバ上でやってしまおう,と.

用意するものは以下の通り.

  • MP4Box ( ports: multimedia/gpac-libgpac )
  • FAAC ( ports: audio/faac )
  • mpg123 ( ports: audio/mpg123 )

作業はこんな手順で.


 MP4Box -aviraw audio infile.avi
 MP4Box -aviraw video infile.avi
 mpg123 -w infile_audio.wav infile_audio.mp3
 faac -q 100 -b 160 -c 48000 --mpeg-vers 4 --obj-type Main infile_audio.wav
 MP4Box -fps 29.97 -add infile_video.h264 -add infile_audio.aac infile.mp4

うーん……TMPGEnc4XP の avi 出力の時点で AAC にエンコードできれば手順がひとつなくせるのだけどなぁ. あと MP4Box の入力ファイル名に日本語(UTF8)が使えないぞ.どーなってんだ.

とまぁ,ここまでやって, なんか途中の MP4Box -aviraw video で抽出する H.264 データのファイルサイズがおかしいことに気づいた. 元の AVI ファイルを作る際のパラメタが悪くて変なデータになって途中で切れているのでは, とか予想して,パラメタ変更してエンコ仕込んで寝よう.

動画ファイルいじってたらまる 1日潰してしまったが, いろいろと知識が増えたからまぁよしとしよう……

H.264 動画 を AVI コンテナに入れた際の問題点とか   ▽20070103a #コンピュータ #動画圧縮

詳しくはココ

……後でぜったい内容忘れるから書いてあることをメモっておこう.


そもそもの問題点

VFW インタフェースと AVI コンテナは基本的に「Bフレーム」を扱えない. 古臭いテクノロジなので「Bフレーム」みたいな最新テクノロジには対応できないのだ.

「Bフレーム」を使いたかったら,できることといったらふたつくらい.

  1. んな古いテクノロジはさっさと捨てて,.MP4 を DirectShow 経由で使うとかする.
  2. 何とかして対応できるためにハックと開発をする.

ふたつのハックの方法

ハックとしては 2種類ありうる.

  1. エンコーダがうまいこと処理する(XviD で packed bitstream を使った場合,あと DivX5 も)
  2. デコーダで頑張る(packed bitstream を使ってない時の XviD)

基本的なトコ

まず,vfw/avi で Bフレームがどういう風に扱われてるのか理解しとこう.

通常,コンテナには「I P B B」の順でフレームが格納され,表示の際には「I B B P」の順で出力される.

vfw/avi は「1フレーム読んで 1フレーム出す(1 in, 1 out)」という仕組みになっていて, 1フレーム読み込んだら必ず 1フレーム出力しなきゃならない (エンコードもデコードも両方そう). Bフレームというのは前後ふたつのフレームの情報から間のひとつのフレームを作り出す技術なので, 「2 in, 1 out」という風に動けない vfw/avi ではうまくいかない.

今時の普通のデコーダの挙動を示す.

  1. まず Iフレームを普通に読んで出力する.
  2. 次に Bフレームを出力したいところだが,それには I/P のフレームが必要だ. I は既にデコード済みなので P までのフレームを読んできて Bフレームをデコードし出力. つまり「3 in, 1 out」となる.
  3. 同じように次の Bフレームを出力.
  4. 最後に Pフレームを出力する.

デコード時のハック

まず,やりかたその1.

avi/vfw の「1 in, 1 out」の法則があるので,まずはエンコーダ側で対応しとかなきゃならない. packed bitstream とか呼ばれる手法がこれだ. すなわち,最初の Bフレームが Pフレームと同じ 1フレームに入って, 「I P B B」が「I P+B B N」になるのだ. N というのはフレーム番号だけ持ってる空フレームだ.

その上で,デコーダの挙動はこうなる.

  1. まず Iフレームをデコード
  2. 次に Bフレームをデコード.これは I と P を必要とするが, P は B と一緒に入ってくるのでデコードできる. AVI的には両方で 1フレーム扱いとなっている.
  3. I と P は既に読み込んでるので 2番目の B もデコードできる
  4. 最後に P を出力.

このハックは,1 フレームに 2フレーム分の情報を送ることで, avi/vfw の「1 in, 1 out」の法則をうまく回避できる. が,普通の MPEG4 標準に従って書かれたデコーダは, この packed bitsream を扱うことができない.

やりかたその2.

コンテナには正しく「I P B B」の順にフレームが格納され,デコーダ側でこれを何とかする.

  1. デコーダはまず Iフレームを読み込むが,ここでは空フレームだけを出力する.
  2. 次に Pフレームが入力されるが,ここで最初の Iフレームを出力する. 「1 in, 1 out」の法則は,初回の空フレームも込みで維持されている.
  3. 次に Bフレームが入力されると,ここで I + B + P が揃うので,Bフレームをデコードできる.
  4. 2番目の Bフレームも同様にデコードできる.
  5. 最後に Pフレームを出力.

このハックだと,空フレームを作ることで「1 in, 1 out」のルールに対応できるが, デコーダは入力されたフレームと違うフレームを出力していることになる. が,packed bitsream と違って,MPEG4 標準ではこれを使用するよう定義している.

エンコード時のハック

というわけで,avi/vfw で Bフレームを扱うためのデコード時のハックは 2通りある. さらにエンコード時にもハックがある.

Bフレームをエンコードするには普通は以下の手順が必要となる.

  1. 最初のフレームを Iフレームにエンコードする.
  2. 2番目の,Bフレームとなるべきフレームが入力されるが, Pフレームが来るまでは Bフレームをエンコードすることができない.
  3. 3番目のフレームも同じようにエンコードできない.
  4. 4番目のフレームを Pフレームとしてエンコードする.
  5. I と P が揃ったので,Bフレームをエンコードできる.
  6. 同じように 2番目の Bフレームをエンコードできる.

もちろん,avi/vfw の「1 in, 1 out」の法則により, ステップ 2 と 3 の「何も出力しない」は不可能だ. そこで,エンコーダは「ディレイフレーム(delay frame)」と呼ばれる空フレーム(1バイトの 0x7F のみから成る)を出力する. このディレイフレームは,単に「1 in, 1 out」に従うためだけに出力されるもので, これが MPEG4 標準への準拠を不可能にする.

そこでどんな手段があるだろうか. Virtualdub(mod) は,エンコード中に得たディレイフレームをすべて捨てるという対処をしている. これにより,出力された AVI ファイルにはディレイフレームがなくなる. が,VFW が必ずしもこういうディレイフレームを捨てるフロントエンドで使われるとは限らない.

……AVI とか VFW,これマジどうよw


……けっきょく全部翻訳してしまったw

index