2019年7月10日水曜日

ffmpeg / 正規表現 単語の区切り / map オプション

ffmpegをつかってできるだけ簡単にmp4を作る方法


[avi @ 0x7ffaf7800000] Could not find codec parameters for stream 1 (Audio: mp3 (mp3float) (U[0][0][0] / 0x0055), 48000 Hz, 2 channels, fltp, 128 kb/s): unspecified frame size

が出たときは「-codec:a copy 」をやると良いのかも。。。。

# no conversion just switch container. highly reliable.

ffmpeg -i <INPUT>.avi -codec:v copy -codec:a copy <OUTPUT>.mp4

OR

ffmpeg -i <INPUT>.avi -codec:a copy out.mp4

ffmpeg -i <INPUT>.mkv -vcodec copy <OUTPUT>.mp4

ffmpeg -i sample_input.mkv -vcodec copy sample_output.mp4

for 文をつかってシーケンシャルに数字を振りながらmp4を作る方法


j=0;for i in  *.mkv; do echo $i;  let ++j ; echo $j ; ffmpeg -y -i $i -vcodec copy $j.mp4; done


  • 文の最後に;を書く
  • let をつかってカウンタを加算する
  • ffmpeg -yで既存ファイルがあっても強制上書き
  • forはdo とdoneで受ける
  • 変数は初期化すること


以下と等価となる。

j=0;for i in  *.mkv;
> do echo $i
> let ++j
> echo $j
> ffmpeg -y -i $i -vcodec copy $j.mp4
> done

j=0;for i in *.mp4; do let ++j; mv $j.mp4 hibike_euphonuim_S2E$j.mp4; done


forとsedと正規表現をつかってファイル名を編集しながらmp4を作る方法


  • さいごの「2」で出現順序を指定して置換する。
  • \(<patter>\)で指定して\1で受けてる。
  • -e 大事。これがないと\1 が使えない。(間違い。なくてもOK)



Hibike Euphonium 1 [BD 720p]$ ls *.mp4 | awk '{ print "mv "$1" "$1}' | gsed -e 's/E\([1-9]\)\./E0\1./2'
mv hibike_euphonuim_S1E1.mp4 hibike_euphonuim_S1E01.mp4
mv hibike_euphonuim_S1E10.mp4 hibike_euphonuim_S1E10.mp4
mv hibike_euphonuim_S1E11.mp4 hibike_euphonuim_S1E11.mp4

awk のgensub関数を使えば、sedは使わなくて良いはず。第二引数の"g"はグローバル?例えば2を指定すると2番めにヒットした正規表現だけを処理してくれるらしい。(要研究)

ls *.mp4 | awk '{ print "ls "$1" "gensub("0([1-9])","1\\1","g",$1)}'

map の使い方


$ffmpeg -i <INPUT_FILE> -map 0:0 -map 0:2 <OUTPUT_FILE>

<sample> honomoto@~$ffmpeg -i k01.mkv -map 0:0 -map 0:2 k01.mp4

この場合、k01.mkvには以下のストリームがある。

Stream #0:0(jpn): Video: h264 (High), yuv420p(progressive), 1280x720, SAR 1:1 DAR 16:9, 23.98 fps, 23.98 tbr, 1k tbn, 47.95 tbc (default)
Stream #0:1(eng): Audio: aac (LC), 48000 Hz, stereo, fltp (default)
Metadata:
  title           : Animax Dub, Released by [SrK-Mitsu89]
Stream #0:2(jpn): Audio: aac (HE-AACv2), 48000 Hz, stereo, fltp
Stream #0:3(eng): Subtitle: ass (default)
Stream #0:4(eng): Subtitle: ass

これらのうち、オプション"-map 0:0 -map 0:2"をつかって、0:0と0:2だけを取り込んでファイルに出力する。結果は以下の通り。0:0は0:0に取り込まれる、0:0をスキップしているので0:2が0:1として生成されている。

Stream #0:0(jpn): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 636 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
Metadata:
  handler_name    : VideoHandler
Stream #0:1(jpn): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 127 kb/s (default)

以下、かんたんな説明。

ffmpeg は -iで指定したファイルの順番を0から数えます。またそれぞれのファイルのストリームの順番も0から数えます。

なので-map 0:0 -map 1:0 -map 2:0 と言うのは、
0つ目のファイルの、0番目のストリームと
1つ目のファイルの、0番目のストリームと
2つ目のファイルの、0番目のストリームをそれぞれ0番目、1番目、2番目としてマージするという意味になります。

つまり、<sample>のmapオプション"-map 0:0 -map 0:2"は0つ目のファイルの0番目のストリームとおなじく2番目のストリームをマージして0つ目のファイルの0番目のストリームと1番目のストリームとして出力するという意味になる。


ファイル名変更時のzero padding


~$ head kon2file.list
K-ON!! Ep 01 - Seniors!.mkv
K-ON!! Ep 03 - Drummer!.mkv
K-ON!! Ep 04 - Field Trip!.mkv
<SKIP>
K-ON!! Ep 26 - Visit!.mkv
K-ON!! Ep 27 (OVA) - Plan!.mkv
K-ON!! Ep 5 - Staying Behind!.mkv
K-ON!! Ep 8 - The Future!.mkv

のとき


~$ awk '{print "ffmpeg  -i \""$0"\" -map 0:0 -map 0:2 K-On!!S2E"$3".mp4"}' kon2file.list |sed 's/E\([1-9]\)\.mp4/E0\1.mp4/'

ffmpeg  -i "K-ON!! Ep 01 - Seniors!.mkv" -map 0:0 -map 0:2 K-On!!S2E01.mp4
ffmpeg  -i "K-ON!! Ep 03 - Drummer!.mkv" -map 0:0 -map 0:2 K-On!!S2E03.mp4
ffmpeg  -i "K-ON!! Ep 04 - Field Trip!.mkv" -map 0:0 -map 0:2 K-On!!S2E04.mp4
<SKIP>
ffmpeg  -i "K-ON!! Ep 26 - Visit!.mkv" -map 0:0 -map 0:2 K-On!!S2E26.mp4
ffmpeg  -i "K-ON!! Ep 27 (OVA) - Plan!.mkv" -map 0:0 -map 0:2 K-On!!S2E27.mp4
ffmpeg  -i "K-ON!! Ep 5 - Staying Behind!.mkv" -map 0:0 -map 0:2 K-On!!S2E05.mp4
ffmpeg  -i "K-ON!! Ep 8 - The Future!.mkv" -map 0:0 -map 0:2 K-On!!S2E08.mp4

となる。Zero Paddingされてるところが味噌!ただし、gensub関数を使うほうが楽なので以下を参照すること。

gensub関数を使用したzero padding


gensub関数を使うともっと簡単。\yは単語の区切りを示す。”\y.\y”でキャラクター一文字を示すので、その場合に前に”0”を足してやる。(注意! 他のGNU softwareは単語の区切りに\bを使う)。

~$ awk '{print "ffmpeg -i \""$0"\" K-OnS2E"gensub(/(\y.\y)/,"0\\1","g",$3)".mp4"}'  kon2file.list

ffmpeg -i "K-ON!! Ep 01 - Seniors!.mkv" K-OnS2E01.mp4
ffmpeg -i "K-ON!! Ep 03 - Drummer!.mkv" K-OnS2E03.mp4
ffmpeg -i "K-ON!! Ep 04 - Field Trip!.mkv" K-OnS2E04.mp4
<SKIP>
ffmpeg -i "K-ON!! Ep 27 (OVA) - Plan!.mkv" K-OnS2E27.mp4
ffmpeg -i "K-ON!! Ep 5 - Staying Behind!.mkv" K-OnS2E05.mp4
ffmpeg -i "K-ON!! Ep 8 - The Future!.mkv" K-OnS2E08.mp4

gensubを2回使用して出力結果をさらに調整する


$ ls *.mkv
K-ON! Ep 01 - Dissolution!.mkv                 K-ON! Ep 10 - Another Training Camp!.mkv
K-ON! Ep 02 - Instruments!.mkv                 K-ON! Ep 11 - Crisis!.mkv
K-ON! Ep 03 - Special Lessons!.mkv             K-ON! Ep 12 (Season Finale) - Light Music!.mkv
K-ON! Ep 04 - Training Camp!.mkv               K-ON! Ep 13 (Extra) - Winter Days!.mkv
K-ON! Ep 05 - Advisor!.mkv                     K-ON! Ep 14 (OVA) - Live House!.mkv
K-ON! Ep 06 - School Festival!.mkv             K-ON! Ep 7 - Christmas!.mkv
K-ON! Ep 09 - New Club Member!.mkv             K-ON! Ep 8 - Freshman Reception!.mkv



$ ls *.mkv | awk '{$3=gensub(/(\y.\y)/,"0\\1","g",$3);print "ffmpeg -i \""$0"\" K-OnS1E"$3gensub(/ /,"_","g",$0)".mp4"}'

ffmpeg -i "K-ON! Ep 01 - Dissolution!.mkv" K-OnS1E01K-ON!_Ep_01_-_Dissolution!.mkv.mp4
ffmpeg -i "K-ON! Ep 02 - Instruments!.mkv" K-OnS1E02K-ON!_Ep_02_-_Instruments!.mkv.mp4
ffmpeg -i "K-ON! Ep 03 - Special Lessons!.mkv" K-OnS1E03K-ON!_Ep_03_-_Special_Lessons!.mkv.mp4
<SKIP>
ffmpeg -i "K-ON! Ep 14 (OVA) - Live House!.mkv" K-OnS1E14K-ON!_Ep_14_(OVA)_-_Live_House!.mkv.mp4
ffmpeg -i "K-ON! Ep 07 - Christmas!.mkv" K-OnS1E07K-ON!_Ep_07_-_Christmas!.mkv.mp4
ffmpeg -i "K-ON! Ep 08 - Freshman Reception!.mkv" K-OnS1E08K-ON!_Ep_08_-_Freshman_Reception!.mkv.mp4


最終バージョンはこちら。


  1. $3 をゼロパディングして戻す。
  2. $0の最初から12バイト目までを削って、変数outstringに代入する。
  3. outstringの最後の4バイト(.mkv)を削って戻す。
  4. outstringから"!"を削って、戻す。
  5. 過熱をさけるため1行ごとに60秒休むよう、"\nsleep 60"。を付加する。
  6. 最終的に””で囲まれたもとのファイル名$0と$3,outstring,固定文字列などなどを結合して変換後のファイル名を作成し、組み合わせて最終的なコマンド文字列を生成する。
  7. ゼロパディングは$3=sprintf("%02d", $3)でやったほう良いかも!(「本当の本当の完成バージョン」を参照)

$ ls *.mkv | awk '{$3=gensub(/(\y.\y)/,"0\\1","g",$3);
>  outstring=substr($0,13);
>  outstring=substr(outstring,1,length(outstring)-4);
>  outstring=gensub(/!/,"","g",outstring);
>  print "ffmpeg -i \""$0"\" K-OnS1E"$3gensub(/ /,"_","g",outstring)".mp4\nsleep 60"}'
ffmpeg -i "K-ON! Ep 01 - Dissolution!.mkv" K-OnS1E01-_Dissolution.mp4
sleep 60
ffmpeg -i "K-ON! Ep 02 - Instruments!.mkv" K-OnS1E02-_Instruments.mp4
sleep 60
ffmpeg -i "K-ON! Ep 03 - Special Lessons!.mkv" K-OnS1E03-_Special_Lessons.mp4
sleep 60
ffmpeg -i "K-ON! Ep 04 - Training Camp!.mkv" K-OnS1E04-_Training_Camp.mp4
sleep 60
<SKIP>
ffmpeg -i "K-ON! Ep 13 (Extra) - Winter Days!.mkv" K-OnS1E13(Extra)_-_Winter_Days.mp4
sleep 60
ffmpeg -i "K-ON! Ep 14 (OVA) - Live House!.mkv" K-OnS1E14(OVA)_-_Live_House.mp4
sleep 60
ffmpeg -i "K-ON! Ep 07 - Christmas!.mkv" K-OnS1E07-_Christmas.mp4
sleep 60
ffmpeg -i "K-ON! Ep 08 - Freshman Reception!.mkv" K-OnS1E08-_Freshman_Reception.mp4

本当の本当の完成バージョン


 ls *.mkv | awk '{$3=sprintf("%02d", $3);
 outstring=substr($0,13);
 outstring=substr(outstring,1,length(outstring)-4);
 outstring=gensub(/!/,"","g",outstring);
 print "ffmpeg -i \""$0"\" K-OnS1E"$3gensub(/[ ()]/,"_","g",outstring)".mp4\nsleep 60"}'

可変長で文字を切り出したい時用。注意!!

ls *.mkv | awk '{$3=sprintf("%02d", $3);
match($0,/\s-\s/)
outstring=substr($0,RSTART+2);
outstring=substr(outstring,1,length(outstring)-4);
outstring=gensub(/!/,"","g",outstring);
print "ffmpeg -i \""$0"\" K-OnS1E"$3gensub(/[ ()&,]/,"_","g",outstring)".mp4\nsleep 60"}'

以下でも良かったかも!

ls *.mkv | awk '{$3=sprintf("%02d", $3);
match($0,/-.*-/)
outstring=substr($0,RSTART+RLENGTH);
outstring=substr(outstring,1,length(outstring)-4);
outstring=gensub(/!/,"","g",outstring);
print "ffmpeg -i \""$0"\" K-OnS1E"$3gensub(/[ ()&,]/,"_","g",outstring)".mp4\nsleep 60"}'

正規表現で単語として認められるのはアルファベット、数字、アンダーバーだけなので、注意!

おわり

0 件のコメント: