2013-01-17 113 views
2

我試圖將.m4a文件轉換爲原始PCM文件,以便我可以在Audacity中播放它。使用libavcodec將.m4a轉換爲PCM

根據AVCodecContext,它是一個使用AV_SAMPLE_FMT_FLTP採樣格式的44100 Hz音軌,據我瞭解,當使用avcodec_decode_audio4進行解碼時,我應該得到兩個浮點值數組(每個通道一個)。

我不確定的AVCodecContext的bits_per_coded_sample的意義= 16

不幸的是無畏扮演的結果早在,如果我有原來的軌道上與一些白噪聲混合。

以下是我所做的一些示例代碼。請注意,我還爲使用帶符號16位非交織數據(sample_format = AC_SAMPLE_FMT_S16P)的軌道添加了一個案例,Audacity可以很好地播放。

int AudioDecoder::decode(std::string path) 
{ 
    const char* input_filename=path.c_str(); 

    av_register_all(); 

    AVFormatContext* container=avformat_alloc_context(); 
    if(avformat_open_input(&container,input_filename,NULL,NULL)<0){ 
    printf("Could not open file"); 
    } 

    if(avformat_find_stream_info(container, NULL)<0){ 
     printf("Could not find file info"); 
    } 
    av_dump_format(container,0,input_filename,false); 

    int stream_id=-1; 
    int i; 
    for(i=0;i<container->nb_streams;i++){ 
    if(container->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO){ 
     stream_id=i; 
     break; 
    } 
    } 
    if(stream_id==-1){ 
    printf("Could not find Audio Stream"); 
    } 

    AVDictionary *metadata=container->metadata; 
    AVCodecContext *ctx=container->streams[stream_id]->codec; 
    AVCodec *codec=avcodec_find_decoder(ctx->codec_id); 

    if(codec==NULL){ 
    printf("cannot find codec!"); 
    } 

    if(avcodec_open2(ctx,codec,NULL)<0){ 
    printf("Codec cannot be found"); 
    } 

    AVSampleFormat sfmt = ctx->sample_fmt; 

    AVPacket packet; 
    av_init_packet(&packet); 
    AVFrame *frame = avcodec_alloc_frame(); 

    int buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE+ FF_INPUT_BUFFER_PADDING_SIZE;; 
    uint8_t buffer[buffer_size]; 
    packet.data=buffer; 
    packet.size =buffer_size; 

    FILE *outfile = fopen("test.raw", "wb"); 

    int len; 
    int frameFinished=0; 

    while(av_read_frame(container,&packet) >= 0) 
    { 
     if(packet.stream_index==stream_id) 
     { 
     //printf("Audio Frame read \n"); 
     int len=avcodec_decode_audio4(ctx, frame, &frameFinished, &packet); 

     if(frameFinished) 
     {  
      if (sfmt==AV_SAMPLE_FMT_S16P) 
      { // Audacity: 16bit PCM little endian stereo 
      int16_t* ptr_l = (int16_t*)frame->extended_data[0]; 
      int16_t* ptr_r = (int16_t*)frame->extended_data[1]; 
      for (int i=0; i<frame->nb_samples; i++) 
      { 
       fwrite(ptr_l++, sizeof(int16_t), 1, outfile); 
       fwrite(ptr_r++, sizeof(int16_t), 1, outfile); 
      } 
      } 
      else if (sfmt==AV_SAMPLE_FMT_FLTP) 
      { //Audacity: big endian 32bit stereo start offset 7 (but has noise) 
      float* ptr_l = (float*)frame->extended_data[0]; 
      float* ptr_r = (float*)frame->extended_data[1]; 
      for (int i=0; i<frame->nb_samples; i++) 
      { 
       fwrite(ptr_l++, sizeof(float), 1, outfile); 
       fwrite(ptr_r++, sizeof(float), 1, outfile); 
      } 
      }    
     } 
    } 
} 
fclose(outfile); 
av_close_input_file(container); 
return 0; 

}

我希望我剛剛做了一個幼稚的轉換(最多/少顯著位的問題),但目前我一直無法弄清楚。請注意,Audacity只能導入RAW浮點數據,如果其32位或64位浮點數(大或小)。

感謝您的任何見解。

回答

0

我認爲問題出現在「nb_samples」中。這不完全是你需要的。最好用「linesize [0]」來嘗試。

例子:

char* ptr_l = (char*)frame->extended_data[0]; 
char* ptr_r = (char*)frame->extended_data[1]; 
size_t size = sizeof(float); 
for (int i=0; i<frame->linesize[0]; i+=size) 
{ 
    fwrite(ptr_l, size, 1, outfile); 
    fwrite(ptr_r, size, 1, outfile); 
    ptr_l += size; 
    ptr_r += size;  
} 

它是 「浮動」,再次爲 「int16_t」 一樣。但「大小」將「的sizeof(int16_t)」

0

您必須AC_SAMPLE_FMT_S16P使用AV_SAMPLE_FMT_FLTP的轉換器

How to convert sample rate from AV_SAMPLE_FMT_FLTP to AV_SAMPLE_FMT_S16?

這裏是一個工作示例(在pAudioBuffer你有白鼻子內的PCM數據) :

SwrContext *swr; 
swr=swr_alloc(); 
av_opt_set_int(swr,"in_channel_layout",2,0); 
av_opt_set_int(swr, "out_channel_layout", 2, 0); 
av_opt_set_int(swr, "in_sample_rate",  codecContext->sample_rate, 0); 
av_opt_set_int(swr, "out_sample_rate", codecContext->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_S16P, 0); 
swr_init(swr); 
int16_t * pAudioBuffer = (int16_t *) av_malloc (AUDIO_INBUF_SIZE * 2); 
while(av_read_frame(fmt_cntx,&readingPacket)==0){ 
    if(readingPacket.stream_index==audioSteam->index){ 
    AVPacket decodingPacket=readingPacket; 
     while(decodingPacket.size>0){ 
    int gotFrame=0; 
     int result=avcodec_decode_audio4(codecContext,frame,&gotFrame,&decodingPacket); 
    if(result<0){ 
      av_frame_free(&frame); 
     avformat_close_input(&fmt_cntx); 
     return null; 
     } 
     if(result>=0 && gotFrame){ 
      int data_size=frame->nb_samples*frame->channels; 
      swr_convert(swr,&pAudioBuffer,frame->nb_samples,frame->extended_data,frame->nb_samples); 
      jshort *outShortArray=(*pEnv)->NewShortArray(pEnv,data_size); 
           (*pEnv)->SetShortArrayRegion(pEnv,outShortArray,0,data_size,pAudioBuffer); 
      (*pEnv)->CallVoidMethod(pEnv,pObj,callBackShortBuffer,outShortArray,data_size); 
      (*pEnv)->DeleteLocalRef(pEnv,outShortArray); 
      decodingPacket.size -= result; 
      decodingPacket.data += result; 
     }else{ 
      decodingPacket.size=0; 
      decodingPacket.data=NULL; 
     }} 
    av_free_packet(&decodingPacket); 
    }