MP4のAAC
mp4コンテナのAAC音声でサンプリングレートを半分に誤認する問題がありました。
同じ問題が、ffmpeg と DirectShowで別々に起きていて何か根本的な問題のようです。
1.コンテナとデコーダの関係
mp4コンテナに格納されたAAC音声ストリームにはフレームヘッダがありません。旧来、AVIのように、コンテナとストリームの独立した関係ではないと言うことです。
2.AACのSBR (Spectral Band Replication) 、PS (Parametric Stereo)
旧来のデコーダとの互換性を取る手段として、サンプリングレート、チャネル数を減らしてヘッダに記す方法が採用された、と言うことのようです。
実際に問題のあった、48KHzサンプリング、ステレオの音声を例に説明します。
SBRでは、24KHzにして(おそらく1つ飛びにサンプルを使って)AACのフレームを作ります。このデータは、旧来のAACと互換で、旧来のデコーダはこの部分を再生します。失われる高い周波数部分は別に格納します。旧来のソフトエアで処理していたヘッダ情報にも24KHzと記して置きます。旧来のソフトウエアでは、24KHzで再生され、新しいソフトウエアでは48KHzで再生されるように仕組んであると言うことです。
PSは、ステレオをモノラルにします。2CHに復号するための情報は別に書き、新しいソフトウエアだけが認識すると言うものです。
3.具体的な問題
3.1.ffmpeg
ffmpegで使われているfaad2は、SBR、PSに対応しています。(完全な対応かどうかはわかりませんが、24KHzから48KHzのPCMを出力します。)
ffmpegでは、デコーダはファイルの入出力をしません。AACのフレームデータを受け取って、PCMデータを返します。例として24KHzサンプリングAACフレームから、48KHzサンプリング相当のデータを返します。これを出力コンテナに入れるのは、ffmpegで、ffmpegはmp4コンテナのヘッダの値(24KHz)を信じて付与しています。
3.2.DirectShowフィルタの出力ピンのサンプリングレート
- ffdshowやスプリッタを入れても、Microsoft DTV-DVD AudioDecoder でデコードされます。このデコーダは、SBRをサポートするようで、前述の例では48KHzを出力します。
しかし、Pinの情報は24KHzになっています。
- 同じことを、(DTV-DVD AudioDecoder を削除して)ffdshow(faad2)で試すと、Pinは48KHzになります。
これは、DTV-DVD AudioDecoder の間違いに思えます。
4.実際にSBRが機能しているのか
24KHzサンプリングのPCMデータを、NeroAacEnc でエンコードして作ったファイル(lc24.mp4)は、MediaInfoで 48KHz LC SBR と表示される。また、この lc24.mp4 から aacフレームデータのみを抜き出して lc24.aac を作り、 faad2 でデコードすると48KHzサンプリングのPCMファイルが出来上がる。
MediaInfo も faad2 も、実質 24KHzサンプリングなのに、48KHzと認識しています。
表示やサンプリングレートを見ても実質はわからないようです。
4.1.faad2、NeroAacEnc、MediaInfo
R言語のスクリプトで、13KHzのサイン波を48KHzと24KHzでサンプリングした状態のPCMデータ(48.wav、24.wav)を作りました。
24KHzサンプリングでは 13KHzは認識できないので、そのパワーは 12KHz以下に誤認されることになります。
 |
- #13KHz の SIN波を1分間収集
- #192KHzでサンプリングした状態のデータを作る
- x<-seq(0,by=2*pi*13000/192000,length.out=192000*60)
- y<-sin(x)
- #サンプリングレートが48KHzの状態(4つ飛びに)
- pos<-seq(1,by=4,length.out=(length(x)/4))
- x48<-x[pos]
- y48<-y[pos]
- #サンプリングレートが24KHzの状態(8つ飛びに)
- pos<-seq(1,by=8,length.out=(length(x)/8))
- x24<-x[pos]
- y24<-y[pos]
- #確認のためプロット
- # 背景に 1ms=192サンプル
- plot(x[1:192],y[1:192],type="l",col="cyan",lwd=1,axes=F,xlab="",ylab="")
- par(new=T)
- plot(x48[1:48],y48[1:48],type="b",lty="dashed",pch="x",col="red",lwd=1,axes=F,xlab="",ylab="")
- par(new=T)
- plot(seq(0,to=1,length.out=24),y24[1:24],type="b",lty="dotted",col="blue",lwd=1,axes=F,xlab="",ylab="")
- axis(1)
- mtext("時間(ms)",1,line=2)
- axis(2)
- mtext("振幅",2,line=2)
- title(main="13KHzの音を24KHzと48KHzでサンプリング")
- #音を聞いて見るためにWAVファイルに出力
- source("WavIO_R.R") #これは一度だけ
- #48KHzサンプリングレート
- tmp<-matrix(0,ncol=length(y48)*2)
- for( i in 1:length(y48)){
- tmp[i*2-1]=y48[i]*30000
- tmp[i*2]=y48[i]*30000}
- wav16write("48.wav",tmp,2,48000)
- #24KHzサンプリングレート
- tmp<-matrix(0,ncol=length(y24)*2)
- for( i in 1:length(y24)){
- tmp[i*2-1]=y24[i]*30000
- tmp[i*2]=y24[i]*30000}
- wav16write("24.wav",tmp,2,24000)
-
- #48KHz サンプリングのFFT
- tmp<-fft(y48[1:48000])#1秒分をFFT
- f48<-sqrt(Re(tmp)*Re(tmp)+Im(tmp)*Im(tmp))
- plot(1:24000,f48[1:24000],type="l",xlab="Hz",ylab="Power")
- title(main="48KHzでサンプリングしたときのFFTの結果")
-
- tmp<-fft(y24[1:24000])#1秒分をFFT
- f24<-sqrt(Re(tmp)*Re(tmp)+Im(tmp)*Im(tmp))
- plot(1:12000,f24[1:12000],type="l",xlab="Hz",ylab="Power")
- title(main="24KHzでサンプリングしたときのFFTの結果")
|
 |
 |
48.wav、24.wav を NeroAacEnc で、-lc オプションを指定して、エンコードします。それぞれ、48.mp4、24.mp4とします。
48.mp4、24.mp4 から、ffmepgで、 -acodec copy を使ってフレームデータのみの 48.aac、24.aac を作ります。
48.aac、24.aac を、faad.exe(faad2)でデコードして、faad48a.wav、faad24a.wav を作ります。
48.mp4、24.mp4 を、faad.exe(faad2)でデコードして、faad48b.wav、faad24b.wav を作ります。
| |
MediaInfo |
備考 |
| 48.mp4 |
48.0KHz,2チャンネル,AAC(Version 4)(LC) |
|
| 24.mp4 |
48.0KHz,2チャンネル,AAC(Version 4)(LC)(SBR) |
24KHzは、SBR付きと認識される |
| 48.aac |
48.0KHz,2チャンネル,AAC(ATDS)(Version 4)(LC) |
|
| 24.aac |
48.0KHz,2チャンネル,AAC(ATDS)(Version 4)(LC)(SBR) |
24KHzは、SBR付きと認識される |
| faad48a.wav |
48.0KHz,2チャンネル,PCM(Microsoft) |
|
| faad24a.wav |
48.0KHz,2チャンネル,PCM(Microsoft) |
mp4コンテナにないとSBRを実行 |
| faad48b.wav |
48.0KHz,2チャンネル,PCM(Microsoft) |
|
| faad24b.wav |
24.0KHz,2チャンネル,PCM(Microsoft)
|
mp4コンテナにあるときはOK |
サンプリングレートが 24KHzなのに、48KHzのSBRと誤認します。当然、13KHzは復号されません。
4.2.DTV-DVD AudioDecoder は、高い周波数を復元するか
前述のように DTV-DVD AudioDecoder は、出力としては 48KHz なのに、Pin情報は 24KHz といった問題があります。しかし、ffdshow フィルタが使えず、常にこれが使われてしまいます。
このフィルタの出力は、Pin情報が正しくないだけで、実質 48KHzサンプリング(SBR有効)になっているのでしょうか。
左図から見て、DTV-DVD AudioDecoder は、SBRサポートのようです。
|
|