職場で廻っていたメールが(もちろんtypoですが)
「~ですの。」
になっていたので、つい「なんで、『白井黒子』がこんなところにいるんだ…」とまぜっかえしたら、
「それはだれ?」と突っ込まれてしまい、『レールガン』とかの話をするはめに。( 来年年男の中年としては、ちとハズカシイ。笑)
それはともかく、「マージ作業」の自動化はなんとかなりました。
必要なものは、ext_bs.exe,faad.exe,tsMuxeR.exeです。ext_bs.exeはここで、faad.exeはここ(FAAD2v2.7 for Win32)で、tsMuxeR.exeはここから。
faad -i <AACファイル名> とすると、
C:\>faad -i [映]「28週後…_WOWOW1_05_11_2009_03_09_02.wav.aac
*********** Ahead Software MPEG-4 AAC Decoder V2.7 ******************
Build: May 13 2009 Copyright 2002-2004: Ahead Software AG
http://www.audiocoding.com
Floating point version
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
**************************************************************************
[映]「28週後…」_WOWOW1_05_11_2009_03_09_02.wav.aac file info:
ADTS, 6024.768 sec, 320 kbps, 48000 Hz
のように、AAC
形式のオーディオ・ファイルの長さが表示されます。そこで、TS形式のビデオから、tsMuxeR
でAAC形式の2
ch音声を抽出し、 AAC形式のファイルを作り、同じ様にfaad
で長さの情報を抽出します。この二つの長さの差分から、マージの際の遅延を計算し、最終的にtsMuxeR
でマージ します。データの流れとしては図のようになります。
手作業で、毎回これをやるのは面倒くさいので、Rubyのスクリプトを作りました。最後にソースコードは載せます。使い方は、コマンドプロンプトから、
ruby -wKs XX.ts [YY.wav]
とします。XX.tsはHD PVRで作ったtsファイル、YY.wavは同時に録ったWaveファイルです。Waveファイルを省略した場合は、XX.tsの拡張子を.wavにした ファイルを仮定します。出力ファイル名は、「ss入力ファイル名.ts」になります。中間ファイルは今のところn入力ファイルと同じディレクトリに作りますが、コマン ド終了時に消去しないので、作業後に自分で消去してください。
2時間程度のHDのファイルでも作業は、我が家の環境(鈍足5400rpmのHDD)で 10分以内に終わります。いくらH264とはいえ、HDのビデオファイルは大きいので、作業時間は主にHDDの性能に依存します。中間ファイルを作成する (物理)ドライブを別にしたり、ビデオ系の処理と、オーディオ系の処理を同時に処理(マルチプロセス化)すれば、もっと高速になるでしょうが、しばらくこ のままで問題がないか見てから改良することにします。
ちょっと苦労したのは、tsMuxeRの使い方です。GUIから使うのは直感的にわかりやすいのですが、コマンドライン版はよくわかりません。実際の動作 としては、GUIは.metaファイルというパラメータを書いたファイルを作成して、コマンドライン版をバックグラウンドで呼び出しているだけのようです が、コマンドライン版のReadmeファイルが、ロシア語版しかない。 orz
しかたないので、GUI版で作業中に、コマンドプロンプトで、「wmic process」とか実行してどうやって呼び出しているか、「盗み見」してみたりして…(笑)
#ruby -wKs
#
#maac51.rb
# (c) 2009 BO
# Usage : ruby -wKs maac51.rb <XX.ts> [YY.wav]
#
# History
# 2009/11/11 1st beta
#
# tested on ruby 1.8.7 (2009-06-12 patchlevel 174) [i386-mswin32]
#
def readinfofile( fname )
reg = /^ADTS, *(\d*\.?\d*) ?sec/
open( fname ) {|file|
while l = file.gets
if reg =~ l
return $1.to_f
end
end
}
return 0.0
end # def readinfofile( fname )
def pinfo( str )
puts "#### #{$0} #{str}\n"
end # def pinfo( str )
def filecheck( path)
if ! File.exist?( path )
pinfo( "Error. '#{path}' was not created/found. Abort..\n" )
exit(1)
end # if
end # def filecheck( path)
def systemandcheck( cmd )
if ! system( cmd )
pinfo( "Error. Subcommand '#{cmd}' seemed to fail. Abort..\n" )
exit(1)
end
end # def systemandcheck( cmd )
##
##main
##
puts ARGV[0]
puts ARGV[1]
# input files
fn = Hash.new
if ! ARGV[0]
puts "Error. No input files specified. Abort.."
exit 1
end # if
fn[:ts] = File::expand_path( ARGV[0] )
if ! ARGV[1]
# No wave input files specified
dname , fname = File::split( fn[:ts] )
bname = File.basename( fname, ".ts" )
fn[:wav] = "#{dname}/#{bname}.wav"
pinfo( "No wave input files specified. assuming '#{fn[:wav]}'" )
else
fn[:wav] = File::expand_path( ARGV[1] )
end # if
# output file
dname , fname = File::split( fn[:ts] )
fn[:outts] = "#{dname}/ss#{fname}"
fn[:outtsmeta] = "#{fn[:outts]}.meta"
#intermediate file
dname , fname = File::split( fn[:ts] )
bname = File.basename( fname, ".ts" )
fn[:tsaac] = "#{dname}/#{bname}.track_4352.aac"
fn[:tsaacmeta] = "#{fn[:tsaac]}.meta"
fn[:tsaacinfo] = "#{fn[:tsaac]}.info"
fn[:_6chaac] = "#{fn[:wav]}.6ch.aac"
fn[:_6chaacinfo] = "#{fn[:_6chaac]}.info"
puts fn[:ts]
puts fn[:wav]
puts ""
puts fn[:tsaac]
puts fn[:tsaacmeta]
puts fn[:tsaacinfo]
puts ""
puts fn[:_6chaac]
puts fn[:_6chaacinfo]
puts ""
puts fn[:outts]
puts fn[:outtsmeta]
puts ""
puts File.dirname(fn[:tsaac])
# exit(0)
#default offset
defalutOffset = -100.0 # in ms
##main start
#### video file
pinfo("extract aac from ts file by tsMuxeR" )
filecheck( fn[:ts] )
# makeing meta file, note that file name in meta file must be with full path
open( fn[:tsaacmeta] , "w") {|file|
file.puts( "MUXOPT --no-pcr-on-video-pid --new-audio-pes --demux --vbr --vbv-len=500\n" )
file.puts( "A_AAC, \"#{fn[:ts]}\", timeshift=-99ms, track=4352\n" )
}
filecheck( fn[:tsaacmeta] )
puts cmd ="tsMuxeR \"#{fn[:tsaacmeta]}\" \"#{File.dirname(fn[:tsaac])}\""
systemandcheck( cmd )
filecheck( fn[:tsaac] )
puts "#### #{$0} make length info of the aac file by faad2"
puts cmd ="faad -i \"#{fn[:tsaac]}\" 2> \"#{fn[:tsaacinfo]}\""
systemandcheck( cmd )
filecheck( fn[:tsaacinfo] )
length_tsaac = readinfofile( fn[:tsaacinfo] )
puts "ts(aac) length = #{length_tsaac.to_s} sec\n"
#### audio file
pinfo "extract aac from wave file by ext_bs"
filecheck( fn[:wav] )
puts cmd = "ext_bs \"#{fn[:wav]}\" \"#{fn[:_6chaac]}\""
systemandcheck( cmd )
pinfo "make length info of the aac file by faad2"
filecheck( fn[:_6chaac] )
puts cmd ="faad -i \"#{fn[:_6chaac]}\" 2> \"#{fn[:_6chaacinfo]}\""
systemandcheck( cmd )
filecheck( fn[:_6chaacinfo] )
length_6chaac = readinfofile( fn[:_6chaacinfo] )
puts "6ch aac length = #{length_6chaac.to_s} sec\n"
offset = ((length_tsaac - length_6chaac ) * 1000.0 + defalutOffset).to_i # in ms
pinfo "offset is #{offset.to_s}"
#### merge files
# makeing meta file, note that file name in meta file must be with full path
open( fn[:outtsmeta], "w") {|file|
file.puts( "MUXOPT --no-pcr-on-video-pid --new-audio-pes --vbr --vbv-len=500")
file.puts( "V_MPEG4/ISO/AVC, \"#{fn[:ts]}\", fps=29.970, insertSEI, contSPS, track=4113")
file.puts( "A_AAC, \"#{fn[:_6chaac]}\", timeshift=#{offset.to_s}ms" )
}
filecheck( fn[:outtsmeta] )
pinfo( "merge files by tsMuxeR" )
puts cmd ="tsMuxeR \"#{fn[:outtsmeta]}\" \"#{fn[:outts]}\""
systemandcheck( cmd )
#EOF
# vim:set ts=8 sts=2 sw=2 tw=0 expandtab: