Audio 使用libavcodec将.m4a转换为PCM

Audio 使用libavcodec将.m4a转换为PCM,audio,ffmpeg,decoding,pcm,libavcodec,Audio,Ffmpeg,Decoding,Pcm,Libavcodec,我正在尝试将.m4a文件转换为原始PCM文件,以便在Audacity中播放它 根据AVCodecContext,这是一个44100 Hz的音轨,使用采样格式AV_sample_FMT_FLTP,据我所知,当使用avcodec_decode_audio4解码时,我应该得到两个浮点值数组(每个通道一个) 我不确定AvcodeContext的位每编码样本=16的重要性 不幸的是,Audacity播放结果时,就好像我看到原始曲目中混入了一些白噪声一样 下面是我所做工作的一些示例代码。请注意,我还为使用有

我正在尝试将.m4a文件转换为原始PCM文件,以便在Audacity中播放它

根据AVCodecContext,这是一个44100 Hz的音轨,使用采样格式AV_sample_FMT_FLTP,据我所知,当使用avcodec_decode_audio4解码时,我应该得到两个浮点值数组(每个通道一个)

我不确定AvcodeContext的位每编码样本=16的重要性

不幸的是,Audacity播放结果时,就好像我看到原始曲目中混入了一些白噪声一样

下面是我所做工作的一些示例代码。请注意,我还为使用有符号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;   
int音频解码器::解码(std::字符串路径)
{
const char*input_filename=path.c_str();
av_寄存器_all();
AVFormatContext*容器=avformat_alloc_context();
if(avformat\u open\u input(&container,input\u filename,NULL,NULL)codec->codec\u type==AVMEDIA\u type\u AUDIO){
流_id=i;
打破
}
}
如果(流_id==-1){
printf(“找不到音频流”);
}
AVDictionary*元数据=容器->元数据;
AVCodecContext*ctx=container->streams[stream\u id]->codec;
AVCodec*codec=AVCodec\u find\u解码器(ctx->codec\u id);
如果(编解码器==NULL){
printf(“找不到编解码器!”);
}
if(avcodec_open2(ctx,codec,NULL)sample_fmt;
数据包;
av_初始_数据包(&数据包);
AVFrame*frame=avcodec_alloc_frame();
int buffer_size=AVCODEC_MAX_AUDIO_FRAME_size+FF_INPUT_buffer_PADDING_size;;
uint8_t缓冲区[缓冲区大小];
数据=缓冲区;
packet.size=缓冲区大小;
文件*outfile=fopen(“test.raw”、“wb”);
内伦;
int frameFinished=0;
而(av_读取_帧(容器和数据包)>=0)
{
if(packet.stream\u index==stream\u id)
{
//printf(“音频帧读取”);
int len=avcodec\u decode\u audio4(ctx、帧、帧完成和数据包);
如果(框架完成)
{       
如果(sfmt==AV_样本_FMT_S16P)
{//Audacity:16位PCM小端立体声
int16_t*ptr_l=(int16_t*)帧->扩展数据[0];
int16_t*ptr_r=(int16_t*)帧->扩展_数据[1];
对于(int i=0;inb_样本;i++)
{
fwrite(ptr_l++,sizeof(int16_t),1,outfile);
fwrite(ptr_++,sizeof(int16_t),1,outfile);
}
}
否则如果(sfmt==AV\U样本\U FMT\U FLTP)
{//Audacity:big-endian 32位立体声起始偏移量7(但有噪声)
float*ptr_l=(float*)帧->扩展_数据[0];
float*ptr_r=(float*)帧->扩展_数据[1];
对于(int i=0;inb_样本;i++)
{
fwrite(ptr_l++,sizeof(float),1,outfile);
fwrite(ptr_++,sizeof(float),1,outfile);
}
}            
}
}
}
fclose(输出文件);
av_关闭_输入_文件(容器);
返回0;
}

我希望我只是做了一个简单的转换(大多数/不太重要的位问题),但目前我还无法解决。请注意,Audacity只能在其32位或64位浮点(大或小尾端)时导入原始浮点数据

感谢您的帮助。

我认为问题出在“nb_样本”中。这并不完全是您需要的。最好尝试使用“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;    
}
char*ptr_l=(char*)帧->扩展_数据[0];
char*ptr_r=(char*)帧->扩展_数据[1];
size\u t size=sizeof(浮动);
for(int i=0;i线性化[0];i+=size)
{
写入(ptr_l,尺寸,1,输出文件);
写入(ptr_r,尺寸,1,输出文件);
ptr_l+=尺寸;
ptr_r+=尺寸;
}

它代表“float”,对“int16_t”重复相同的操作。但是“size”将是“sizeof(int16_t)”

您必须在AC_SAMPLE_FMT_S16P中使用AV_SAMPLE_FMT_FLTP转换器

以下是一个工作示例(在pAudioBuffer中,您的pcm数据位于白鼻子内):

SwrContext*swr;
swr=swr_alloc();
av_opt_set_int(swr,“通道内布局”,2,0);
av_opt_set_int(swr,“输出通道布局”,2,0);
av_opt_set_int(swr,“采样率”,编解码器上下文->采样率,0);
av_opt_set_int(swr,“输出采样率”,编码上下文->采样率,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*pAudioBuffer=(int16*t*)av\u malloc(音频输入大小*2);
while(av_read_frame(fmt_cntx,&readingPacket)==0){
if(readingPacket.stream_index==audioSteam->index){
AVPacket decodingPacket=读取数据包;
while(decodingPacket.size>0){
int-gotFrame=0;
int result=avcodec_decode_audio4(编解码器上下文、帧、哥特帧和解码包);
如果(结果=0&&gotFrame){
int data_size=frame->nb_samples*frame->channels;
swr_转换(swr和pAudioBuffer,帧->nb_样本,帧->扩展_数据,帧->nb_样本);
jshort*outshortaray=(*pEnv)->newshortaray(pEnv,数据大小);
(*pEnv)->设置Shortarray区域(pEnv,outShortArray,0,数据大小,pAudioBuffer);
(*pEnv)->CallVoidMethod(pEnv、pObj、callBackShortBuffer、outShortArray、数据大小);
(*pEnv)->DeleteLocalRef(pEnv,outShortArray);
decodingPacket.size-=结果;
decodingPacket.data+=结果;
}否则{
decodingPacket.size=0;
decodingPacket.data=NULL;
}}
av_免费_数据包(和解码数据包);
}
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);
    }