1. 程式人生 > >ffmpeg pcm碼流編碼為aac

ffmpeg pcm碼流編碼為aac

根據雷霄驊博文介紹非常清楚

 http://blog.csdn.net/leixiaohua1020/article/details/25430449

 可是為什麼我這麼做了卻出來奇怪的聲音?經過仔細研究發現是我們使用的ffmpeg版本有了很大的變化造成,我使用的是ffmpeg-2.8.1,對音訊編碼處理已經有了很大的變化。

檢視aac編碼

AVCodec ff_aac_encoder = {

    .name           = "aac",

    .long_name      = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"),

    .type           = AVMEDIA_TYPE_AUDIO,

    .id             = AV_CODEC_ID_AAC,

    .priv_data_size = sizeof(AACEncContext),

    .init           = aac_encode_init,

    .encode2        = aac_encode_frame,

    .close          = aac_encode_end,

    .supported_samplerates = mpeg4audio_sample_rates,

    .capabilities   = AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY |

                      AV_CODEC_CAP_EXPERIMENTAL,

    .sample_fmts    = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP,

                                                     AV_SAMPLE_FMT_NONE },

    .priv_class     = &aacenc_class,

};

支援的轉換格式為AV_SAMPLE_FMT_FLTPpcm的格式為AV_SAMPLE_FMT_S16

而老版的

ffmpeg 的則是:AV_SAMPLE_FMT_S16;

1.  pCodecCtx = audio_st->codec;  

2.     pCodecCtx->codec_id = fmt->audio_codec;  

3.     pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;  

4.     pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;  

5.     pCodecCtx->sample_rate= 44100;  

6.     pCodecCtx->channel_layout=AV_CH_LAYOUT_STEREO;  

7.     pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);  

8.     pCodecCtx->bit_rate = 64000;   

所以在新版本上實現轉換就先要將輸入格式轉化為AV_SAMPLE_FMT_FLTP,用什麼方法可以實現呢,ffmpeg已經給我們提供了API:swr_convert

int attribute_align_arg swr_convert(

struct SwrContext *s,

uint8_t *out_arg[SWR_CH_MAX],

int out_count,                                      

const uint8_t *in_arg [SWR_CH_MAX],

int  in_count)

呼叫該函式之前需要設定格式

        /**

         * Create a resampler context for the conversion.

         * Set the conversion parameters.

         * Default channel layouts based on the number of channels

         * are assumed for simplicity (they are sometimes not detected

         * properly by the demuxer and/or decoder).

         */

        *resample_context = swr_alloc_set_opts(NULL,

                                              av_get_default_channel_layout(output_codec_context->channels),

                                              output_codec_context->sample_fmt,

                                              output_codec_context->sample_rate,

                                              av_get_default_channel_layout(input_codec_context->channels),

                                              input_codec_context->sample_fmt,

                                              input_codec_context->sample_rate,

                                              0, NULL);

 /** Open the resampler with the specified parameters. */

        if ((error = swr_init(*resample_context)) < 0) {

            fprintf(stderr, "Could not open resample context\n");

            swr_free(resample_context);

            return error;

        }

格式的具體轉換可以參考ffmpeg sampleresampling_audio.c可以對轉換的方法和流程有一個大體的瞭解。

轉換完成後就可以按照老版的流程來執行了。

	pCodecCtx = audio_st->codec;
	pCodecCtx->codec_id = AV_CODEC_ID_AAC;
	pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
	pCodecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP;
	pCodecCtx->sample_rate= 8000;
	pCodecCtx->channel_layout=AV_CH_LAYOUT_MONO;//AV_CH_LAYOUT_STEREO;
	pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
	pCodecCtx->bit_rate = 64000;  
	/** Allow the use of the experimental AAC encoder */
	pCodecCtx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;

	//Show some information
	av_dump_format(pFormatCtx, 0, out_file, 1);

	pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
	if (!pCodec){
		printf("Can not find encoder!\n");
		goto end;
	}
	if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0){
		printf("Failed to open encoder!\n");
		goto end;
	}

	//input case
    pFormatCtx_input = avformat_alloc_context();
	
    audio_st_input = avformat_new_stream(pFormatCtx_input, 0);
    if (!audio_st_input) {
        fprintf(stderr, "Could not alloc stream\n");
        goto end;
    }
	pCodecCtx_input = audio_st_input->codec;
	pCodecCtx_input->codec_id = AV_CODEC_ID_PCM_S16LE;
	pCodecCtx_input->codec_type = AVMEDIA_TYPE_AUDIO;
	pCodecCtx_input->sample_fmt = AV_SAMPLE_FMT_S16;
	pCodecCtx_input->sample_rate= 8000;
	pCodecCtx_input->channel_layout=AV_CH_LAYOUT_MONO;//AV_CH_LAYOUT_STEREO;//AV_CH_LAYOUT_MONO;
	pCodecCtx_input->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
	pCodecCtx_input->bit_rate = 64000;  
	/** Allow the use of the experimental AAC encoder */
	pCodecCtx_input->frame_size = 1024;

    /* allocate source and destination samples buffers */

    ret = av_samples_alloc_array_and_samples(&src_data, &src_linesize, pCodecCtx_input->channels,
                                             pCodecCtx_input->frame_size, pCodecCtx_input->sample_fmt, 0);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate source samples\n");
        goto end;
    }
	
    /* compute the number of converted samples: buffering is avoided
     * ensuring that the output buffer will contain at least all the
     * converted input samples */
    max_dst_nb_samples = dst_nb_samples =
        av_rescale_rnd(pCodecCtx_input->frame_size, pCodecCtx->sample_rate, pCodecCtx_input->sample_rate, AV_ROUND_UP);
	
    /* buffer is going to be directly written to a rawaudio file, no alignment */
    ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, pCodecCtx->channels,
                                             dst_nb_samples, pCodecCtx->sample_fmt, 0);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate destination samples\n");
        goto end;
    }

	dst_bufsize = av_samples_get_buffer_size(&dst_linesize, pCodecCtx->channels,
												 dst_nb_samples, pCodecCtx->sample_fmt, 1);
	if (dst_bufsize < 0) 
	{
			fprintf(stderr, "Could not get sample buffer size\n");
			goto end;
	}

	src_bufsize = av_samples_get_buffer_size(&src_linesize, pCodecCtx_input->channels,
												pCodecCtx_input->frame_size, pCodecCtx_input->sample_fmt, 1);
	if (src_bufsize < 0) 
	{
			fprintf(stderr, "Could not get sample buffer size\n");
			goto end;
	}
	pCodecCtx->frame_size = dst_nb_samples;
	//resample case
    /** Initialize the resampler to be able to convert audio sample formats. */
    if (init_resampler(pCodecCtx_input, pCodecCtx,
                       &resample_context))
        goto end;

	
	if (init_fifo(&fifo, pCodecCtx))
        goto end;
        
        
    	avformat_write_header(pFormatCtx,NULL);

    /**
     * Loop as long as we have input samples to read or output samples
     * to write; abort as soon as we have neither.
     */
    while (1) {
        /** Use the encoder's desired frame size for processing. */
        static int output_frame_size = dst_nb_samples;
        const int src_nb_samples = pCodecCtx_input->frame_size;
		static int cnt = 0;
		int data_written;
		if (fread((char*)src_data[0], 1, src_bufsize, in_file) <= 0){
			printf("Failed to read raw data! \n");
			break;
		}else if(feof(in_file)){
			printf("end of file\n");
			break;
		}
		
		cnt++;
        /**
         * Make sure that there is one frame worth of samples in the FIFO
         * buffer so that the encoder can do its work.
         * Since the decoder's and the encoder's frame size may differ, we
         * need to FIFO buffer to store as many frames worth of input samples
         * that they make up at least one frame worth of output samples.
         */
        while (av_audio_fifo_size(fifo) < output_frame_size) {
			
			/* compute destination number of samples */
			dst_nb_samples = av_rescale_rnd(swr_get_delay(resample_context, pCodecCtx_input->sample_rate) +
											pCodecCtx_input->frame_size, pCodecCtx->sample_rate, pCodecCtx_input->sample_rate, AV_ROUND_UP);
			if (dst_nb_samples > max_dst_nb_samples) {
				
				av_freep(&dst_data[0]);
				ret = av_samples_alloc(dst_data, &dst_linesize, pCodecCtx->channels,
									   dst_nb_samples, pCodecCtx->sample_fmt, 1);
				if (ret < 0)
					break;
				max_dst_nb_samples = dst_nb_samples;
				
				printf("!!!!dst_nb_samples=%d changed!!!!\n",dst_nb_samples);
			}

            /**
             * Decode one frame worth of audio samples, convert it to the
             * output sample format and put it into the FIFO buffer.
             */

			
	        /* convert to destination format */
	        ret = swr_convert(resample_context, dst_data, dst_nb_samples, (const uint8_t **)src_data, src_nb_samples);
	        if (ret < 0) {
	            fprintf(stderr, "Error while converting\n");
	            goto end;
	        }
			dst_bufsize = av_samples_get_buffer_size(&dst_linesize, pCodecCtx->channels,
													 ret, pCodecCtx->sample_fmt, 1);
			if (dst_bufsize < 0) {
				fprintf(stderr, "Could not get sample buffer size\n");
				goto end;
			}
			/** Add the converted input samples to the FIFO buffer for later processing. */
			
			if (add_samples_to_fifo(fifo, dst_data,dst_nb_samples))
				goto end;

			
			output_frame_size = dst_nb_samples;
			#if 1
			if (av_sample_fmt_is_planar(pCodecCtx->sample_fmt)) 
			{
				int bytes_sample = av_get_bytes_per_sample(pCodecCtx->sample_fmt);
				//for (int i = 0; i < pCodecCtx->channels; i++)
				//	printf("pCodecCtx->channels=%d,bytes_sample=%d,dst_linesize=%d\n",pCodecCtx->channels,bytes_sample,dst_linesize);
				fwrite(dst_data[0], 1, dst_bufsize, dst_file);
			}
			#endif
        }

        /**
         * If we have enough samples for the encoder, we encode them.
         * At the end of the file, we pass the remaining samples to
         * the encoder.
         */
         
        while (av_audio_fifo_size(fifo) >= output_frame_size ||
               ( av_audio_fifo_size(fifo) > 0))
        {
            /**
             * Take one frame worth of audio samples from the FIFO buffer,
             * encode it and write it to the output file.
             */
            if (load_encode_and_write(fifo, pFormatCtx,pCodecCtx))
                break;
        }
    }

	flush_encoder(pFormatCtx,0);

	//Write Trailer
	av_write_trailer(pFormatCtx);