2013-01-17 5 views
2

.m4a 파일을 원시 PCM 파일로 변환하려고하므로 Audacity에서 다시 재생할 수 있습니다.libavcodec을 사용하여 .m4a를 PCM으로 변환하십시오.

AVCodecContext에 따르면 avcodec_decode_audio4를 사용하여 디코딩 할 때 AVSAMPLE_FMT_FLTP 샘플 형식을 사용하는 44100Hz 트랙으로, 두 개의 부동 소수점 값 배열 (각 채널 당 하나씩)을 가져와야합니다.

나는

(16)는 불행하게도 대담 다시 내가 원래 트랙이 약간의 화이트 노이즈와 혼합되어있는 경우와 같은 결과를 재생 = AVCodecContext의 bits_per_coded_sample의 중요성 확실 해요.

다음은 내가 수행 한 작업의 샘플 코드입니다. Audacity가 정상적으로 재생 한 부호있는 16 비트 비 인터리브 데이터 (sample_format = AC_SAMPLE_FMT_S16P)를 사용하는 트랙의 사례도 추가했습니다.

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는 32 비트 또는 64 비트가 플로팅 (크거나 작은 엔디안)되어있는 경우에만 RAW 플로트 데이터를 가져올 수 있습니다.

어떤 통찰력에도 감사드립니다.

답변

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"에 대한 동일한 "부동"에 대한, 그리고 반복합니다. 그러나 "크기"

0

당신은 AC_SAMPLE_FMT_S16P에 AV_SAMPLE_FMT_FLTP의 변환기를 사용한다 "는 sizeof (int16_t)"입니다

다음

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); 
    }