ffmpeg转码

时间:2013-01-23 15:23:23

标签: c audio ffmpeg

我想使用ffmpeg库进行音频转码。现在我有文件,但我只能听到噪音。 我的计划的步骤是: 1)打开输入文件并使用avcodec_decode_audio4以原始格式解码 2)编码并保存原始格式。 我不知道我错在哪里。这是我的代码。

/* 
 * File:   newmain.c
 * Author: antonello
 *
 * Created on 23 gennaio 2013, 11.24
 */

#include <stdio.h>
#include <stdlib.h>


#include <libavutil/samplefmt.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libavcodec/old_codec_ids.h>

static AVCodecContext *get_encoder(int sampleRate, int channels, int audioBitrate)
{ 
    AVCodecContext  *audioCodec;
    AVCodec *codec;



    //Set up audio encoder
    codec = avcodec_find_encoder(CODEC_ID_AAC);
    if (codec == NULL) 
    {
        printf("avcodec_find_encoder: ERROR\n");
        return NULL;
    }
    audioCodec = avcodec_alloc_context();
    audioCodec->bit_rate = audioBitrate;
    audioCodec->sample_fmt = AV_SAMPLE_FMT_S16P;
    audioCodec->sample_rate = sampleRate;
    audioCodec->channels = channels;
    audioCodec->profile = FF_PROFILE_AAC_MAIN;
    audioCodec->channel_layout=AV_CH_LAYOUT_MONO;
    //audioCodec->time_base = (AVRational){1, sampleRate};
    audioCodec->time_base.num  = 1;
    audioCodec->time_base.den  = sampleRate;

    audioCodec->codec_type = AVMEDIA_TYPE_AUDIO;
    if (avcodec_open(audioCodec, codec) < 0) 
    {
        printf("avcodec_open: ERROR\n");
        return NULL;
    }

    return audioCodec;
}


int main(int argc, char** argv) {
  AVFormatContext *aFormatCtx_decoder = NULL;
  AVFormatContext *aFormatCtx_encoder = NULL;
  int             i, audioStream;
  AVPacket        packet_decoder;
  AVPacket        packet_encoder;
  int             got_frame=0;
  int             complete_decode=0;
  int             len;
  AVFrame         *decoded_frame = NULL;
  AVCodecContext  *aCodec_decoderCtx = NULL;
  AVCodec         *aCodec_decoder = NULL;
  FILE            *outfile;
  //reding input file
  avcodec_register_all();

   //register all codecs
    av_register_all();

 //open file
    if(avformat_open_input(&aFormatCtx_decoder, "sample.aac", NULL, NULL)!=0){
        fprintf(stderr, "Could not open source file \n");
        return -1; // Couldn't open file
    }

  // Retrieve stream information
  if(avformat_find_stream_info(aFormatCtx_decoder, NULL)<0){
      fprintf(stderr, "Couldn't find stream information \n");
      return -1; // Couldn't find stream information
  }

  // Dump information about file onto standard error
  //av_dump_format(aFormatCtx_decode, 0, argv[1], 0);

  // Find the first audio stream
  audioStream=-1;

  for(i=0; i<aFormatCtx_decoder->nb_streams; i++) {
    if(aFormatCtx_decoder->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO &&
       audioStream < 0) {
      audioStream=i;
    }
  }
  if(audioStream==-1){
      fprintf(stderr, "File haven't sudio stream \n");
      return -1;
  }

  //get audio codec contex
  aCodec_decoderCtx=aFormatCtx_decoder->streams[audioStream]->codec;
  //get audio codec
  aCodec_decoder = avcodec_find_decoder(aCodec_decoderCtx->codec_id);
  aCodec_decoder->sample_fmts=AV_SAMPLE_FMT_S16P;
  if(!aCodec_decoder) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1;//Unsupported codec!
  }
  //open codec
  // Open codec
  if(avcodec_open2(aCodec_decoderCtx, aCodec_decoder, NULL)<0)
    return -1; // Could not open codec
  // allocate audio frame
  decoded_frame = avcodec_alloc_frame();
  if (!decoded_frame) {
    fprintf(stderr, "Could not allocate audio frame\n");
    return -1;//Could not allocate audio frame
    }
  aCodec_decoderCtx->bit_rate=12000;
  aFormatCtx_encoder=get_encoder(8000,1,12000);
  av_init_packet(&packet_encoder);

  printf("param %d %d %d",aCodec_decoderCtx->sample_fmt,aCodec_decoderCtx->channels,aCodec_decoderCtx->bit_rate);

  outfile = fopen("out.aac", "wb");
    if (!outfile) {
        printf(stderr, "Could not open outfile \n");
        return -1;//Could not open outfile
    }
  while(av_read_frame(aFormatCtx_decoder, &packet_decoder)>=0) {
     // decode frame
     len = avcodec_decode_audio4(aCodec_decoderCtx, decoded_frame, &got_frame, &packet_decoder);
        if (len < 0) {
            fprintf(stderr, "Error while decoding\n");
            return -1;
            }

        if (got_frame){
          avcodec_encode_audio2(aFormatCtx_encoder,&packet_encoder,decoded_frame,&complete_decode);
          if(complete_decode){
          //    printf("complete decode frame");
              fwrite(packet_encoder.data, 1, packet_encoder.size, outfile);
              av_free_packet(&packet_encoder);
          }
        }



    }
  fclose(outfile);
    return (EXIT_SUCCESS);
}

3 个答案:

答案 0 :(得分:1)

您无法设置变量sample_fmts的任意值:

aCodec_decoder->sample_fmts=AV_SAMPLE_FMT_S16P; // It's wrong

将始终使用编解码器设置的参数执行解码。 您必须创建SwrContext并执行到目标的格式转换(SwrContext转换样本格式,采样率和频道布局)

答案 1 :(得分:1)

使用以下代码进行样本格式转换。 你可以在ffmpeg / doc / examples / resampling_audio.c

中得到例子
        SwrContext *swr = swr_alloc();


        av_opt_set_int(node_handle->swr,        "in_channel_layout",    decoded_frame->channel_layout,          0);
        av_opt_set_int(node_handle->swr,        "out_channel_layout",   encoder_ctx->channel_layout,    0);

        av_opt_set_int(node_handle->swr,        "in_sample_rate",       decoded_frame->sample_rate,             0);
        av_opt_set_int(node_handle->swr,        "out_sample_rate",      encoder_ctx->sample_rate,       0);

        av_opt_set_sample_fmt(swr, "in_sample_fmt",        decoded_frame->format,                  0); 
        av_opt_set_sample_fmt(swr, "out_sample_fmt",       encoder_ctx->sample_fmt,        0);

        swr_init(swr);

        uint8_t* swr_out_data;
        int linesize;
        av_samples_alloc(&swr_out_data,
                             linesize,
                             encoder_ctx->nb_channels,
                             decoded_frame->nb_samples,
                             encoder_ctx->sample_fmt,
                             0
                         );
        swr_convert(swr,&swr_out_data, decoded_frame->nb_samples, decoded_frame->data, decoded_frame->nb_samples);

答案 2 :(得分:0)

修改为此,工作正常

aCodec_decoder->sample_fmts=audioCodec->sample_fmt;