note
1.wav格式中,音频数据未经过压缩,直接封装即可
2.对于编码器的选择,应选择和pcm裸数据一致的编码器(本次实际不须编码)
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::MuxPCMToWAV(const char* pcm_file, const char* wav_file)
{
const AVOutputFormat* out_fmt = nullptr;
AVFormatContext* fmt_ctx = nullptr;
const AVCodec* codec = nullptr;
AVCodecContext* codec_ctx = nullptr;
AVStream* avstream = nullptr;
AVPacket* avpacket = nullptr;
AVFrame* avframe = nullptr;
int ret = -1;
FILE* in_fp = nullptr;
int sample_fmt_is_planar = 0;
size_t n = 0;
int frame_data_bytes = 0;
codec = avcodec_find_encoder(AV_CODEC_ID_PCM_F32LE);
if (!codec)
{
printf("avcodec_find_encoder error\n");
goto END;
}
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx)
{
printf("avcodec_alloc_context3 error\n");
goto END;
}
codec_ctx->sample_fmt = AV_SAMPLE_FMT_FLT; // f32le
codec_ctx->sample_rate = 44100;
codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
codec_ctx->channels = av_get_channel_layout_nb_channels(codec_ctx->channel_layout);
ret = avcodec_open2(codec_ctx, codec, nullptr);
if (ret < 0)
{
printf("avcodec_open2 error(%s)\n", GetFfmpegERR(ret));
goto END;
}
printf("frame_size:%d\n", codec_ctx->frame_size);
avframe = av_frame_alloc();
if (!avframe)
{
printf("av_frame_alloc error\n");
goto END;
}
avframe->format = AV_SAMPLE_FMT_FLT;
avframe->sample_rate = 44100;
avframe->channel_layout = AV_CH_LAYOUT_STEREO;
avframe->channels = av_get_channel_layout_nb_channels(avframe->channel_layout);
avframe->nb_samples = 1024;
ret = av_frame_get_buffer(avframe, 0);
if (ret < 0)
{
printf("av_frame_get_buffer error(%s)\n", GetFfmpegERR(ret));
goto END;
}
ret = av_samples_get_buffer_size(nullptr,
avframe->channels,
avframe->nb_samples,
(AVSampleFormat)(avframe->format),
1);
if (ret < 0)
{
printf("av_samples_get_buffer_size error(%s)\n", GetFfmpegERR(ret));
goto END;
}
frame_data_bytes = ret;
avpacket = av_packet_alloc();
if (!avpacket)
{
printf("av_packet_alloc error\n");
goto END;
}
in_fp = fopen(pcm_file, "rb");
if (!in_fp)
{
printf("fopen error\n");
goto END;
}
ret = avformat_alloc_output_context2(&fmt_ctx, nullptr, nullptr, wav_file);
if (ret < 0)
{
printf("avformat_alloc_output_context2 error(%s)\n", GetFfmpegERR(ret));
goto END;
}
out_fmt = fmt_ctx->oformat;
avstream = avformat_new_stream(fmt_ctx, codec);
if (!avstream)
{
printf("avformat_new_stream error\n");
goto END;
}
ret = avcodec_parameters_from_context(avstream->codecpar, codec_ctx);
if (ret < 0)
{
printf("avcodec_parameters_from_context error(%s)\n", GetFfmpegERR(ret));
goto END;
}
ret = avio_open(&(fmt_ctx->pb), wav_file, AVIO_FLAG_READ_WRITE);
if (ret < 0)
{
printf("avio_open error(%s)\n", GetFfmpegERR(ret));
goto END;
}
ret = avformat_write_header(fmt_ctx, nullptr);
if (ret < 0)
{
printf("avformat_write_header error(%s)\n", GetFfmpegERR(ret));
goto END;
}
while (1)
{
if (feof(in_fp))
{
break;
}
sample_fmt_is_planar = av_sample_fmt_is_planar((AVSampleFormat)(avframe->format));
if (sample_fmt_is_planar)
{
n = fread(avframe->data[0], sizeof(uint8_t), frame_data_bytes / 2, in_fp);
if ((int)n != (frame_data_bytes / 2))
{
printf("n != (frame_data_bytes / 2)\n");
}
n = fread(avframe->data[1], sizeof(uint8_t), frame_data_bytes / 2, in_fp);
if ((int)n != (frame_data_bytes / 2))
{
printf("n != (frame_data_bytes / 2)\n");
}
}
else
{
n = fread(avframe->data[0], sizeof(uint8_t), frame_data_bytes, in_fp);
if ((int)n != frame_data_bytes)
{
printf("n != (frame_data_bytes)\n");
}
}
ret = avcodec_send_frame(codec_ctx, avframe);
if (ret < 0)
{
if (ret == AVERROR(EAGAIN))
{
printf("read output first\n");
}
else
{
printf("avcodec_send_frame error(%s)\n", GetFfmpegERR(ret));
break;
}
}
while (1)
{
ret = avcodec_receive_packet(codec_ctx, 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;
}
}
ret = av_write_frame(fmt_ctx, avpacket);
if (ret < 0)
{
printf("av_write_frame error(%s)\n", GetFfmpegERR(ret));
av_packet_unref(avpacket);
goto END;
}
av_packet_unref(avpacket);
}
}
ret = avcodec_send_frame(codec_ctx, nullptr);
while (1)
{
ret = avcodec_receive_packet(codec_ctx, 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;
}
}
ret = av_write_frame(fmt_ctx, avpacket);
if (ret < 0)
{
printf("av_write_frame error(%s)\n", GetFfmpegERR(ret));
av_packet_unref(avpacket);
goto END;
}
av_packet_unref(avpacket);
}
ret = av_write_trailer(fmt_ctx);
if (ret < 0)
{
printf("av_write_trailer error(%s)\n", GetFfmpegERR(ret));
goto END;
}
END:
if (fmt_ctx)
{
avformat_free_context(fmt_ctx);
fmt_ctx = nullptr;
}
if (in_fp)
{
fclose(in_fp);
in_fp = nullptr;
}
if (avframe)
{
av_frame_free(&avframe);
avframe = nullptr;
}
if (avpacket)
{
av_packet_free(&avpacket);
avpacket = nullptr;
}
if (codec_ctx)
{
avcodec_free_context(&codec_ctx);
codec_ctx = nullptr;
}
}