2008年4月30日水曜日

MM: PS3用にH.264で動画を圧縮(インタレ保持)

手順だけメモ.前提となる各ツールのバージョンとかはちゃんと確認していない.古すぎると多分ダメ.

MPEG-2 TS のファイルがある場合.仮に a.ts とする.

まず,DGIndex(DGMPGDec 中のプログラム) で .d2v と音声トラックを作る.
仮に m.d2v としておこう.
コケるようなら,予め ts に mpeg2repair をかけておく.
mpeg2repair はフリーだが,1.0.1.5 より前のバージョンでは期限がどうこう言われて使えなかったりするので注意.
DGIndex で ts を開いた際,ストリームの PID を指定する必要がある場合がある.やり方は こちら を参照.

.d2v ができたら,AVISynth -> x264 に流し込む.具体的には,m.avs を用意し,m.bat を走らせる.現時点(20080430)での設定は次の通り.冗長だったり矛盾してたりはあるやも.
[m.avs]
# --------------------------------------------------------------------------------
PPath = "C:\Program Files\AviSynth 2.5\plugins\"
VFPPath = "C:\DGMPGDec\"
LoadVFAPIPlugin(VFPPath + "DGVfapi.vfp", "D2VSource")

D2VSource("m.d2v")
# Top Field First
AssumeFrameBased().ComplementParity()
FlipVertical()
Crop(0,0,1440,1080,align=true)
ConvertToYV12(interlaced=true)

return last
# --------------------------------------------------------------------------------

DGVfapi のせいなのか,縦(垂直) 1080 の元ファイルを読み込むと,縦 1088 で出てくる.
AVIUtl で開くと下に 8 ピクセル分余計なものが付いているようなので,素直に上から 1080 ピクセルを Crop で抜き出している.1088 のままだと PS3 が非対応のデータと言って再生してくれない(ファーム v2.30).横(水平)が 1440 か 1920 かはソースによる.横 1440 なら,この次の x264 のオプションで --sar 4:3 を入れる(→ARは1440*(4/3):1080=16:9).
Crop 呼び出し時に align=true はどっちでもいいのだろう.速度だけの問題?よくわからない.

次に,キャプチャした HuffYUV + wav(aacストリームを内包) な .avi がある場合.仮に m.avi とする.
このときは,AVIUtl でカット・結合して,wav は ext_bs で aac を抜き出しておく.映像成分は音声なしの .avi にしておいて,次のような AVISynth スクリプトで読み込む.
[m.avs]

# --------------------------------------------------------------------------------

OpenDMLSource("m.avi")
# Top Field First

AssumeFrameBased().ComplementParity()

ConvertToYV12(interlaced=true)


return last

# --------------------------------------------------------------------------------
AVIUtl のプロジェクトファイル (.aup) を読み込んだ方がいい時もあるかもしれない.

いずれにせよ,読み込んでインターレース保持で YV12 に変換すればいいんである.
なお,TFF (TopFieldFirst) か BFF (BottomFieldFirst) かは,AVIUtl の 60fps 読み込みなどで確認してからにするべし.

さて,.avs が用意できたら,次のようなバッチファイルを走らせる.

[m.bat]
rem --------------------------------------------------------------------------------
echo off

rem PS3 再生を目的とした設定.インタレ保持.
rem 基本的に,x264 --longhelp の順.

set INAVS="m.avs"
set OUT264="m.264"

rem ********************************************************************
rem Frame-type options
set OPT_F1=--keyint 300 --min-keyint 15 --scenecut 75 --vbv-maxrate 25000 --vbv-bufsize 62500
set OPT_F2=--bframes 1 --ref 3
set OPT_F3=--deblock -3:-1
set OPT_F4=--interlaced
set OPT_F=%OPT_F1% %OPT_F2% %OPT_F3% %OPT_F4%

rem ********************************************************************
rem Ratecontrol
set OPT_R1=--crf 22
set OPT_R2=--qpmin 12 --qpmax 28 --qpstep 8 --qcomp 0.8
set OPT_R=%OPT_R1% %OPT_R2%

rem ********************************************************************
rem Analysis
set OPT_A1=--me umh --merange 16 --subme 6 --b-rdo --bime
set OPT_A2=--no-fast-pskip --no-dct-decimate
set OPT_A3=
set OPT_A4=--deadzone-intra 4 --deadzone-inter 8
set OPT_A5=--cqm jvt
set OPT_A=%OPT_A1% %OPT_A2% %OPT_A3% %OPT_A4% %OPT_A5%

rem ********************************************************************
rem Input/Output
set OPT_IO1=--sar 4:3
set OPT_IO2=--level 4.2
set OPT_IO3=--threads 1 --progress
set OPT_IO4= -o %OUT264% %INAVS%
set OPT_IO=%OPT_IO1% %OPT_IO2% %OPT_IO3% %OPT_IO4%

rem ********************************************************************
set OPT_ALL=%OPT_P% %OPT_F% %OPT_R% %OPT_A% %OPT_IO%

echo %OPT_ALL%

c:\bin\x264.exe %OPT_ALL%
rem --------------------------------------------------------------------------------

--sar は前述のとおりソースによる.
この x264 のオプション設定は,--crf 18 くらいを念頭においているので,より大きな crf 値(より低いビットレート)ではあまり効率が良くないかもしれない.
ageha さんのところ によると,avc qp 18 == asp qp 2, avc qp 24 == asp qp 4 ということになる.
Xvid で HD の動画をエンコードする際,自分の伝統としては q=2.0 を使ってきていたから,そのままいけば x264 では qp 18 なのだろうが,いかんせんサイズが大きすぎる.
ちなみに,crf は柔軟で賢い qp 位のつもりで使っているが,いいのかな.
deblock を弱めてあるのは,確かバンディングを消すためだったと思った.昔の試行錯誤を系統的に整理していないので,オプション類の設定の根拠がよくわからんのです.

以上のような設定で,手持ちの 2 GHz 前後のマシン群ではエンコード速度が 2.5fps を超えることがないのがなんとも.
ちょっと重すぎ.コアがいっぱいあったら --threads を増やせばいいのだろう.

最後に,できた m1.264 と,音声の aac を
mp4box --fps 29.970030 -add m1.264:par=4:3 -add m1.aac:delay=-398 -new m.mp4
のように mux すればできあがり.
ただ,delay の指定の仕方とほんとに効いてるのかがよくわからない.
あと,音ズレについてまだ経験が少なくてよくわからない.
まとまっているところがあるようなので参考にしたい.

色空間はよくわからないでやってる.要調査.

なお,ツール類は, videohelp がよくカバーしているようだ.



2008年4月22日火曜日

Tips_DTP: 文字主体のスキャン画像を小さくする

検証なしで手順だけ.

  • JTrim で開く.
    1. ガンマ 0.6 程度にして文字をくっきりさせる.
    2. 明るさ 10, コントラスト 20 程度にしてノイズを消しとばす.
    3. リサイズ.
    4. 色解像度を変更.4bit とか.
    5. PNG で保存.

これで結構縮まる.自動化してくれるソフトがありそうなものだ.
この手の画像は,JPEGよりPNG/GIF系の方が明らかに良い.
PNG 最適化や BMP の可逆圧縮は,fairealにいろいろ記事があったなぁ.



2007年10月5日金曜日

matlab: なんちゃって構造体

空の構造体は

>> a = struct([])
a =
0x0 struct array with no fields.

とすれば簡単に作れる.では,「フィールドを持たないけど空ではない構造体」はどうすれば作れるか?

すぐに思いつくのは,rmfield を使って,フィールドを消して行くやり方だろう.

>> b.foo = []; a = rmfield(b, 'foo')
a =
1x1 struct array with no fields.

これはかっこ悪いので却下.だが実現は出来ることがわかる.
では,rmfield はどうやってこれを実現しているか?
rmfield は実は組み込み関数でなく .m 関数なので,type rmfield して中身をのぞくと,どうやら cell2struct を呼び出しているらしい.
ならばはじめから cell2struct を使えばいいのである.しかも cell2struct は組み込み関数だから,わりと根源的なやり方といえるだろう.

>> a = cell2struct(cell(0,1),{})
a =
1x1 struct array with no fields.

おお,できた.これでいいや.

しかし,恒例の whos でみると

>> whos a
  Name      Size                    Bytes  Class
  a         1x1                         0  struct array
Grand total is 0 elements using 0 bytes

のように,メモリが割り当てられていないではないか.しかも a の repmat で b を作ってみても,b も Bytes は 0 のままである.

実際にメモリを割り当てるにはフィールドを定義しないといけないらしい.AMD64 な Linux 上で AMD64 な MatlabR2006a を使った場合,

>> b = repmat(a,[100,1]);
>> whos b
  Name      Size                    Bytes  Class
  b       100x1                         0  struct array
Grand total is 0 elements using 0 bytes
>> b(1).foo = '';
>> whos b
  Name      Size                    Bytes  Class
  b       100x1                       952  struct array
Grand total is 100 elements using 952 bytes

となるが,同じことを IA32 な Windows 上で IA32 な Matlab6.5.1 を使って行った場合,

>> b=repmat(a,[100,1]);
>> whos b
  Name      Size                   Bytes  Class
  b       100x1                        0  struct array
Grand total is 0 elements using 0 bytes
>> b(1).foo = '';
>> whos b
  Name      Size                   Bytes  Class
  b       100x1                      520  struct array
Grand total is 100 elements using 520 bytes

となる.なんで違うんでしょう.




2007年8月19日日曜日

oblivion: なんとなく screenshot: 1


Sophia ※がある人を Cloud Ruler Temple に連れて行くと,集合した Blades の前で演説が行われた.

※Sophia = プレイヤー



2007年8月13日月曜日

matlab: なんちゃってcomplex

matlab (今回は 6.5.1 でしか試してません)は複素数について直感に反する挙動を示すことがある.例を見てみよう.

>> A = repmat(complex(0),[10,1]);
>> whos A
  Name      Size                   Bytes  Class
  A        10x1                      160  double array (complex)
Grand total is 10 elements using 160 bytes
>> A(end) = complex(1,0);
>> whos A
  Name      Size                   Bytes  Class
  A        10x1                       80  double array
Grand total is 10 elements using 80 bytes

complex じゃなくなってる.およ?一応確認すると,A に代入した値は実数でなく複素数と認識されているはずだ.

>> clear a; a=complex(1,0); whos a
  Name      Size                   Bytes  Class
  a         1x1                       16  double array (complex)
Grand total is 1 element using 16 bytes

となるからだ.ただし,入力引数に対する inputname のように,出力引数についての情報取得機構が関数 complex 内で働いているとすると,よくわからない話になるかもしれない.

一つ考えられる仮説は,「虚部が全て 0 の配列は実数型にされてしまう」というものだ.実際,その方がメモリ効率やら計算効率やらよくなる気はする.

念のため,虚部が 0 でない複素数を代入すれば,配列は実数型に変換されることは無い.

>> A = repmat(complex(0),[10,1]);
>> A(end)=complex(0,1);
>> whos A
  Name      Size                   Bytes  Class
  A        10x1                      160  double array (complex)
Grand total is 10 elements using 160 bytes

そして,要素を虚部が 0 の複素数に順に置き換えていくと,

>> A=complex([1,2],[3,4]);
>> A(1)=complex(real(A(1))); whos A
  Name      Size                   Bytes  Class
  A         1x2                       32  double array (complex)
Grand total is 2 elements using 32 bytes
>> A(2)=complex(real(A(2))); whos A
  Name      Size                   Bytes  Class
  A         1x2                       16  double array
Grand total is 2 elements using 16 bytes

となった.ここまでは前述の仮説で当たっていそうである.

しかし,もちろん話はこれで終わらない.次の例を見てみよう.

>> A=zeros(1,2);
>> A(:)=complex(0);
>> whos A
  Name      Size                   Bytes  Class
  A         1x2                       32  double array (complex)
Grand total is 2 elements using 32 bytes

なんと配列は複素数のままであり,これは前述の仮説と矛盾する.ところがさらに,代入の方法を変えると,

>> A=zeros(1,2);
>> A(1:end)=complex(0);
>> whos A
  Name      Size                   Bytes  Class
  A         1x2                       16  double array
Grand total is 2 elements using 16 bytes

となって前述の仮説が復活する.どうなってるのという話である.

ここで新たに,「全代入(whole substition とか?)」という概念を考えてみる.
全代入と考えるのは次の4つ.

  1. A = B;
  2. A(:) = B;
  3. A = B(:);
  4. A(:) = B(:);
変数間の代入で虚部 0 でも complex を維持するには,どうやら厳密にこの4形式しか許されないようだ.
たとえば2次元配列で A(:,:) としてもダメだったし,列ベクトルで A(:,1) としてもダメだった.
この概念を利用して立てた仮説がこれだ:
「全代入では愚直な代入が行われ,それ以外では値の取り出し・代入いずれかで可能なら虚部が 0 の複素数は実数に落ちる」
いまのところこの仮説で説明できるような気がする.
この他に,左辺が全参照(全代入と同じ気分)で右辺が「適当な」式なら,やはり実数に落ちないようだ.以下の例を参照のこと.

>> A=complex(rand(3));
>> A(:)=complex(0); whos A
  Name      Size                   Bytes  Class
  A         3x3                      144  double array (complex)
Grand total is 9 elements using 144 bytes
>> A(:)=complex(zeros(3)); whos A
  Name      Size                   Bytes  Class
  A         3x3                      144  double array (complex)
Grand total is 9 elements using 144 bytes

いや~.重箱の隅つつくといろいろ出てくるなぁ.
ちなみに,大方の予想通り

>> A=complex(rand(3));
>> A(:,:)=complex(0); whos A

  Name      Size                   Bytes  Class
  A         3x3                       72  double array
Grand total is 9 elements using 72 bytes
>> A=complex(rand(3));
>> A(:)=complex(zeros(3)) + 1; whos A
  Name      Size                   Bytes  Class
  A         3x3                       72  double array
Grand total is 9 elements using 72 bytes


となる.もういいって?
今回の現象は,subsref, subsasgn, subsindex と型キャストの実装のコンボで生じるんだろうけど,意図された仕様なんですかねぇ.



2007年8月11日土曜日

MM: 携帯動画の変換(mp4へ)

以前の記事にも書いた携帯で録画した動画を何とかするのの続き.
YAMB は MP4Box のフロントエンドであるらしく,Options->General->MP4Box->View or Edit MP4Box Command Line. にチェックを入れると,どうやって MP4Box を呼び出しているかがわかる.
これを調べると,次のようなバッチファイルでいけそうだ.

"C:\Program Files\YAMB\MP4Box.exe" -avi 1 "%~f1"
"C:\Program Files\YAMB\MP4Box.exe" -raw 2 "%~f1"
"C:\Program Files\YAMB\MP4Box.exe" -add "%~d1%~p1%~n1_track1.avi" -add "%~d1%~p1%~n1_track2.amr" "%~f1.mp4"
del "%~d1%~p1%~n1_track1.avi"
del "%~d1%~p1%~n1_track2.amr"

この内容でバッチファイルを作り,そのショートカットを Send To フォルダに入れておく.
すると,hogehoge.3g2 を右クリックし,「送る」で hogehoge.3g2.mp4 に変換できるようになる.
このバッチファイルは,w43h で録画すると出来る .3g2 を前提にしており,track2 が amr 形式の音声トラックだと仮定している.

バッチパラメータ( %~f1 等)についてはykr さんのページや,Windows 一般に共通なのかわからないけどMicrosoft TechNetのページなどを参照.

ちなみに,track 1 の抽出を -raw 1 とすると .cmp ファイルができる.これでも .mp4 へ mux できたが,なぜか後ろの方が再生できなかったりした..avi 経由だと問題なかった.なんで??

さて,あとは mpeg2 に変換して DVD に焼くところだ.



2007年6月12日火曜日

matlab: 呼び出しの調査

matlab 上で関数を呼び出すと疑似コンパイル(p-code)され,メモリに残る.
メモリ上の p-code buffer に存在する m-file の名前を見るには,inmem という関数を使う.
これで,実際に呼ばれた関数の一覧が得られる.

関数のコードを走査して再帰的に依存を調べるには,depfun という関数を使う.
depfun の賢さは限定的なので,もれなくわかると期待してはいけない.depdir も同様.

profile なんかも結構役に立つ.単に echo してみるのも面白いかもしれない.