使用libav codeC转换.M4A来PCM [英] Convert .m4a to PCM using libavcodec

查看:2470
本文介绍了使用libav codeC转换.M4A来PCM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想一个.m4a的文件转换为原始PCM文件,这样我可以在Audacity的回放。

I'm trying to convert a .m4a file to raw PCM file so that I can play it back in Audacity.

据该AV codecContext它是用样本格式AV_SAMPLE_FMT_FLTP它,我的理解,当德$ C $使用AV codec_de code_audio4 cded,我应该得到两个数组一个44100赫兹的轨道的浮点值(每个信道)。

According to the AVCodecContext it is a 44100 Hz track using the sample format AV_SAMPLE_FMT_FLTP which, to my understanding, when decodeded using avcodec_decode_audio4, I should get two arrays of floating point values (one for each channel).

我是不确定的意义AV codecContext的bits_per_ coded_sample = 16

I'm unsure of the significance of the AVCodecContext's bits_per_coded_sample = 16

不幸的是无畏扮演的结果早在,如果我有原来的轨道上与一些白噪声混合在一起。

Unfortunately Audacity plays the result back as if I have the original track is mixed in with some white noise.

下面是我一直在做的事情的一些示例code。请注意,我还添加了一个案例,它使用16位签署非交错数据(sample_format = AC_SAMPLE_FMT_S16P)的轨道,这Audacity的回放罚款。

Here is some sample code of what I've been done. Note that I've also added a case for a track that uses signed 16bit non-interleaved data (sample_format = AC_SAMPLE_FMT_S16P), which Audacity plays back fine.

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;   

}

我希望我刚刚做了一个天真的转换(最多/少显著位问题),但在present我一直无法弄清楚。需要注意的是无畏则仅可导入RAW浮点数据的32位或64位浮点(或大​​或小端)。

I'm hoping I've just done a naive conversion (most/less significant bit issues), but at present I've been unable to figure it out. Note that Audacity can only import RAW float data if its 32bit or 64 bit float (big or little endian).

感谢您的任何见解。

推荐答案

您必须使用AV_SAMPLE_FMT_FLTP的转换器AC_SAMPLE_FMT_S16P

You must use a converter of AV_SAMPLE_FMT_FLTP in AC_SAMPLE_FMT_S16P

<一个href=\"http://stackoverflow.com/questions/14989397/how-to-convert-sample-rate-from-av-sample-fmt-fltp-to-av-sample-fmt-s16\">How到采样率转换到AV_SAMPLE_FMT_FLTP AV_SAMPLE_FMT_S16?

下面是一个工作示例(在pAudioBuffer你有白鼻内的PCM数据):

Here is a working example (in pAudioBuffer you have pcm data within white nose):

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

这篇关于使用libav codeC转换.M4A来PCM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆