2013-02-20 6 views
7

私はavcodec_decode_audio3でffmpegでpcmにaacをデコードしています。しかし、それはAV_SAMPLE_FMT_FLTPサンプルフォーマット(PCM 32bit Float Planar)にデコードし、AV_SAMPLE_FMT_S16(PCM 16bit signed - S16LE)が必要です。サンプルレートをAV_SAMPLE_FMT_FLTPからAV_SAMPLE_FMT_S16に変換するにはどうすればよいですか?

私はffmpegが-sample_fmtでこれを簡単に行うことができることを知っています。私はコードで同じことをしたいが、私はまだそれを理解することができませんでした。

audio_resampleが機能しませんでした:エラーメッセージ:....で変換に失敗しました。

+0

あなたがこれに答えをうまくしましたか?同じ問題に直面しています –

答えて

35

編集日2012年9月9日:これを行うにはlibswresampleの使い方を工夫してください...もっと早く!

最後の2〜3年のある時点で、FFmpegのAACデコーダの出力形式がAV_SAMPLE_FMT_S16からAV_SAMPLE_FMT_FLTPに変更されました。つまり、各オーディオチャンネルには独自のバッファがあり、各サンプル値は-1.0から+1.0にスケーリングされた32ビットの浮動小数点値です。

AV_SAMPLE_FMT_S16の場合、データは1つのバッファにあり、サンプルはインターリーブされてお​​り、各サンプルは-32767〜+32767の符号付き整数です。

AV_SAMPLE_FMT_S16として実際にオーディオが必要な場合は、自分で変換する必要があります。

1. libswresample(推奨)

#include "libswresample/swresample.h" 

... 

SwrContext *swr; 

... 

// Set up SWR context once you've got codec information 
swr = swr_alloc(); 
av_opt_set_int(swr, "in_channel_layout", audioCodec->channel_layout, 0); 
av_opt_set_int(swr, "out_channel_layout", audioCodec->channel_layout, 0); 
av_opt_set_int(swr, "in_sample_rate",  audioCodec->sample_rate, 0); 
av_opt_set_int(swr, "out_sample_rate", audioCodec->sample_rate, 0); 
av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); 
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); 
swr_init(swr); 

... 

// In your decoder loop, after decoding an audio frame: 
AVFrame *audioFrame = ...; 
int16_t* outputBuffer = ...; 
swr_convert(&outputBuffer, audioFrame->nb_samples, audioFrame->extended_data, audioFrame->nb_samples); 

そして、それはあなたがしなければならないのです。私はそれを行うには、2つの方法を考え出しました!

AVCodecContext *audioCodec; // init'd elsewhere 
AVFrame *audioFrame;   // init'd elsewhere 
AVPacket packet;    // init'd elsewhere 
int16_t* outputBuffer;  // init'd elsewhere 
int out_size = 0; 
... 
int len = avcodec_decode_audio4(audioCodec, audioFrame, &out_size, &packet); 
:あなたはこのようにそれをデコードする音声パケットを持っているとき

2.

はC(推奨されません、元の答えは、)あなたのデコードループでそう

、手でそれを実行します。

そして、あなたは、オーディオのフルフレームを持っている場合、その後、あなたはかなり簡単に変換できます。

// Convert from AV_SAMPLE_FMT_FLTP to AV_SAMPLE_FMT_S16 
    int in_samples = audioFrame->nb_samples; 
    int in_linesize = audioFrame->linesize[0]; 
    int i=0; 
    float* inputChannel0 = (float*)audioFrame->extended_data[0]; 
    // Mono 
    if (audioFrame->channels==1) { 
     for (i=0 ; i<in_samples ; i++) { 
      float sample = *inputChannel0++; 
      if (sample<-1.0f) sample=-1.0f; else if (sample>1.0f) sample=1.0f; 
      outputBuffer[i] = (int16_t) (sample * 32767.0f); 
     } 
    } 
    // Stereo 
    else { 
     float* inputChannel1 = (float*)audioFrame->extended_data[1]; 
     for (i=0 ; i<in_samples ; i++) { 
      outputBuffer[i*2] = (int16_t) ((*inputChannel0++) * 32767.0f); 
      outputBuffer[i*2+1] = (int16_t) ((*inputChannel1++) * 32767.0f); 
     } 
    } 
    // outputBuffer now contains 16-bit PCM! 

を私は...わかりやすくするために目を物事のカップルを残してきましたモノラル・パスでのクランプは、理想的にはステレオ・パスで複製する必要があります。コードは簡単に最適化できます。

+0

私は関連する問題がありますが、今回はS16からS16Pに変換する必要があります。最新のffmpegはlibmp3lameエンコーディングのためにS16Pが必要です。あなたが見てみるとうれしいよ:http://stackoverflow.com/questions/18131389/how-to-convert-av-sample-fmt-s16-to-av-sample-fmt-s16p – frankish

+0

ルーベン、あなたはこのコードをまだ持っていますか?このコンバージョンを有効にしようとしていますが、いくつか問題があります。あなたがリンクを投稿できるなら、私は完全な実用的な解決策を見たいと思います。前もって感謝します。 –

+0

私はもうオプション2のコードを持っていません... libswresampleを使用することは、この問題を解決するための賢い方法です。あなたが持っている問題は何ですか? –

2

ありがとうReubenこれに対する解決策。私は、真っ直ぐなffmpeg -i file.wavと比較すると、サンプル値のいくつかがややずれていることがわかりました。変換では、値にround()を使用しているようです。

変換を行うために、私はあなたがチャンネルの任意の量のために働くために修正の入札でやったことをやった:私は0.11.1 ffmpegのから行った

if (audioCodecContext->sample_fmt == AV_SAMPLE_FMT_FLTP) 
{ 
    int nb_samples = decoded_frame->nb_samples; 
    int channels = decoded_frame->channels; 
    int outputBufferLen = nb_samples & channels * 2; 
    short* outputBuffer = new short[outputBufferLen/2]; 

    for (int i = 0; i < nb_samples; i++) 
    { 
     for (int c = 0; c < channels; c++) 
     { 
      float* extended_data = (float*)decoded_frame->extended_data[c]; 
      float sample = extended_data[i]; 
      if (sample < -1.0f) sample = -1.0f; 
      else if (sample > 1.0f) sample = 1.0f; 
      outputBuffer[i * channels + c] = (short)round(sample * 32767.0f); 
     } 
    } 

    // Do what you want with the data etc. 

} 

- > 1.1.3および変更を見つけました邪魔なサンプルフォーマットの私は、AV_SAMPLE_FMT_S16にrequest_sample_fmtを設定してみましたが、AVECのデコーダはAV_SAMPLE_FMT_FLTP以外のものをサポートしていないようです。

+0

偉大な追加、ありがとう – frankish

+0

私はlibswresampleを使ってより良い方法で私の答えを更新しました。それは驚くほど簡単です。 –

+0

@BradMitchellどうすればこのようなことができますか? http://stackoverflow.com/questions/18131389/how-to-convert-av-sample-fmt-s16-to-av-sample-fmt-s16pを見ていただけますか? – frankish

5

FFMPEGから2つのリサンプル関数が見つかりました。パフォーマンスが良いかもしれません。

  1. avresample_convert() http://libav.org/doxygen/master/group__lavr.html
  2. swr_convert()http://spirton.com/svn/MPlayer-SB/ffmpeg/libswresample/swresample_test.c
+0

あなたは間違いなくAlbertの正式なラインにいました。今日はパフォーマンスに関する苦情がありましたので、この変換を行うための最適化された方法を探して、libswresampleが私の新しい親友です。上記の私の答えは必要なコードで更新されました。 –

関連する問題