version
#define LIBSWRESAMPLE_VERSION_MAJOR 2
#define LIBSWRESAMPLE_VERSION_MINOR 9
#define LIBSWRESAMPLE_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_MINOR 31
#define LIBAVCODEC_VERSION_MICRO 102
code
void CFfmpegOps::EncodePCMToMP3(const char *pcm_file, const char *mp3_file)
{
if ((!pcm_file) || (!mp3_file))
{
return;
}
FILE *in_fp = nullptr;
FILE *out_fp = nullptr;
AVCodecContext *codec_ctx = nullptr;
const AVCodec *codec = nullptr;
AVFrame *pcm_avframe = nullptr; // pcm file里的AVFrame
AVFrame *codec_avframe = nullptr; // 编码器接受的AVFrame
int pcm_data_bytes = 0;
AVPacket *mp3_avpacket = nullptr;
int ret = -1;
size_t n = 0;
int sample_fmt_is_planar = 0;
int64_t pts = 0;
struct SwrContext *swr_ctx = nullptr; // 音频帧转换器
AVChannelLayout src_channel_layout;
AVChannelLayout dest_channel_layout;
in_fp = fopen(pcm_file, "rb");
if (!in_fp)
{
printf("fopen error\n");
goto END;
}
out_fp = fopen(mp3_file, "wb");
if (!out_fp)
{
printf("fopen error\n");
goto END;
}
codec = avcodec_find_encoder(AV_CODEC_ID_MP3);
if (!codec)
{
printf("avcodec_find_encoder error\n");
goto END;
}
// mp3编码器是否支持变化的采样样本数量
if (codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)
{
printf("codec AV_CODEC_CAP_VARIABLE_FRAME_SIZE\n");
}
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx)
{
printf("avcodec_alloc_context3 error\n");
goto END;
}
codec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
codec_ctx->sample_rate = 44100;
codec_ctx->channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
codec_ctx->bit_rate = 128000;
codec_ctx->time_base.num = 1;
codec_ctx->time_base.den = codec_ctx->sample_rate;
// 打开编码器
ret = avcodec_open2(codec_ctx, codec, nullptr);
if (ret < 0)
{
printf("avcodec_open2 error:%s\n", GetFfmpegERR(ret));
goto END;
}
codec_avframe = av_frame_alloc();
if (!codec_avframe)
{
printf("av_frame_alloc error\n");
goto END;
}
codec_avframe->format = codec_ctx->sample_fmt;
codec_avframe->sample_rate = codec_ctx->sample_rate;
codec_avframe->channel_layout = codec_ctx->channel_layout;
codec_avframe->channels = codec_ctx->channels;
codec_avframe->nb_samples = codec_ctx->frame_size;
ret = av_frame_get_buffer(codec_avframe, 0);
if (ret < 0)
{
printf("av_frame_get_buffer error(%s)\n", CFfmpegOps::GetFfmpegERR(ret));
goto END;
}
pcm_avframe = av_frame_alloc();
if (!pcm_avframe)
{
printf("av_frame_alloc error\n");
goto END;
}
pcm_avframe->format = AV_SAMPLE_FMT_FLT;
pcm_avframe->sample_rate = 44100;
pcm_avframe->channel_layout = AV_CH_LAYOUT_STEREO;
pcm_avframe->channels = av_get_channel_layout_nb_channels(pcm_avframe->channel_layout);
pcm_avframe->nb_samples = 1024;
// 一帧pcm的相关参数计算
pcm_data_bytes = av_get_bytes_per_sample((AVSampleFormat)(pcm_avframe->format)) * pcm_avframe->channels * pcm_avframe->nb_samples;
ret = av_samples_get_buffer_size(nullptr,
pcm_avframe->channels,
pcm_avframe->nb_samples,
(AVSampleFormat)(pcm_avframe->format),
0);
if (ret != pcm_data_bytes)
{
printf("pcm_data_bytes != av_samples_get_buffer_size\n");
goto END;
}
ret = av_frame_get_buffer(pcm_avframe, 0);
if (ret < 0)
{
printf("av_frame_get_buffer error(%s)\n", CFfmpegOps::GetFfmpegERR(ret));
goto END;
}
mp3_avpacket = av_packet_alloc();
if (!mp3_avpacket)
{
printf("av_packet_alloc error\n");
goto END;
}
ret = av_channel_layout_from_mask(&src_channel_layout, pcm_avframe->channel_layout);
if (ret < 0)
{
printf("av_channel_layout_from_mask error(%s)\n", GetFfmpegERR(ret));
goto END;
}
ret = av_channel_layout_from_mask(&dest_channel_layout, codec_avframe->channel_layout);
if (ret < 0)
{
printf("av_channel_layout_from_mask error(%s)\n", GetFfmpegERR(ret));
goto END;
}
ret = swr_alloc_set_opts2(&swr_ctx,
&dest_channel_layout, (AVSampleFormat)(codec_avframe->format), codec_avframe->sample_rate,
&src_channel_layout, (AVSampleFormat)(pcm_avframe->format), pcm_avframe->sample_rate,
0, nullptr);
if (ret < 0)
{
printf("swr_alloc_set_opts2 error(%s)\n", GetFfmpegERR(ret));
goto END;
}
ret = swr_init(swr_ctx);
if (ret < 0)
{
printf("swr_init error(%s)\n", GetFfmpegERR(ret));
goto END;
}
while (1)
{
if (feof(in_fp))
{
printf("feof\n");
break;
}
sample_fmt_is_planar = av_sample_fmt_is_planar((AVSampleFormat)(pcm_avframe->format));
if (sample_fmt_is_planar)
{
n = fread(pcm_avframe->data[0], sizeof(uint8_t), pcm_data_bytes / 2, in_fp);
if ((int)n != (pcm_data_bytes / 2))
{
printf("n != pcm_data_bytes/2\n");
}
n = fread(pcm_avframe->data[1], sizeof(uint8_t), pcm_data_bytes / 2, in_fp);
if ((int)n != (pcm_data_bytes / 2))
{
printf("n != pcm_data_bytes/2\n");
}
}
else
{
n = fread(pcm_avframe->data[0], sizeof(uint8_t), pcm_data_bytes, in_fp);
if ((int)n != pcm_data_bytes)
{
printf("n != bytes_per_frame\n");
}
}
#if 0
ret = swr_convert_frame(swr_ctx, codec_avframe, pcm_avframe);
if (ret < 0)
{
printf("swr_convert_frame error(%s)\n", GetFfmpegERR(ret));
goto END;
}
#else
ret = swr_convert(swr_ctx,
(uint8_t**)(codec_avframe->data), codec_avframe->nb_samples,
(const uint8_t**)(pcm_avframe->data), pcm_avframe->nb_samples);
if (ret < 0)
{
printf("swr_convert error(%s)\n", GetFfmpegERR(ret));
goto END;
}
#endif
codec_avframe->pts = pts;
pts++;
ret = avcodec_send_frame(codec_ctx, codec_avframe);
if (ret < 0)
{
if (ret == AVERROR(EAGAIN))
{
printf("read output first\n");
}
else
{
printf("avcodec_send_frame error(%s)\n", GetFfmpegERR(ret));
goto END;
}
}
else if (ret == 0)
{
// printf("avcodec_send_frame succeed\n");
}
while (1)
{
ret = avcodec_receive_packet(codec_ctx, mp3_avpacket);
if (ret < 0)
{
if (ret == AVERROR(EAGAIN))
{
printf("send input first\n");
break;
}
else
{
printf("avcodec_receive_packet error(%s)\n", GetFfmpegERR(ret));
break;
}
}
else if (ret == 0)
{
// printf("avcodec_receive_packet succeed\n");
n = fwrite(mp3_avpacket->data, sizeof(uint8_t), mp3_avpacket->size, out_fp);
if ((int)n != mp3_avpacket->size)
{
printf("n != mp3_avpacket->size\n");
}
av_packet_unref(mp3_avpacket);
}
}
}
ret = avcodec_send_frame(codec_ctx, nullptr);
while (1)
{
ret = avcodec_receive_packet(codec_ctx, mp3_avpacket);
if (ret < 0)
{
if (ret == AVERROR(EAGAIN))
{
break;
}
else
{
break;
}
}
else if (ret == 0)
{
n = fwrite(mp3_avpacket->data, sizeof(uint8_t), mp3_avpacket->size, out_fp);
av_packet_unref(mp3_avpacket);
}
}
END:
if (swr_ctx)
{
swr_free(&swr_ctx);
swr_ctx = nullptr;
}
if (mp3_avpacket)
{
av_packet_free(&mp3_avpacket);
mp3_avpacket = nullptr;
}
if (codec_avframe)
{
av_frame_free(&codec_avframe);
codec_avframe = nullptr;
}
if (pcm_avframe)
{
av_frame_free(&pcm_avframe);
pcm_avframe = nullptr;
}
if (codec_ctx)
{
avcodec_free_context(&codec_ctx);
codec_ctx = nullptr;
}
if (out_fp)
{
fclose(out_fp);
out_fp = nullptr;
}
if (in_fp)
{
fclose(in_fp);
in_fp = nullptr;
}
}