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_FLTP,而pcm的格式为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 sample:resampling_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);