基于QT+FFMPEG的音视频开发(四)——编码音频
我的大部分学习都来自雷神,没有基础去雷神博客转转,每次都有很多收获。
https://blog.csdn.net/leixiaohua1020/article/details/42658139
一、编码一般步骤
avformat_alloc_output_context2(); //初始化输出码流 avio_open(); //打开输出文件 av_new_stream(); //创建输出码流 avcodec_find_encoder(); //寻找解码器 avcodec_alloc_context3(); //打开解码器上下文 avcodec_open2(); //打开解码器 avformat_write_header(); //写文件头 avcodec_send_frame(); avcodec_receive_packet(); //两步为编码 av_interleaved_write_frame(); //将编码后压缩包写入文件 av_write_trailer(); //写文件尾
主要流程图可以去雷神那看看,对于像我这样的初学者很有帮助。
二、编码
2.1 创建编码器(本文创建AAC)
AVCodec *avcodec = avcodec_find_encoder(AV_CODEC_ID_AAC); if (avcodec == NULL) { //创建失败 return -1; } AVCodecContext *avcodec_context = avcodec_alloc_context3(avcodec); avcodec_context->bit_rate = 64000; avcodec_context->sample_rate = 44100; avcodec_context->sample_fmt = AV_SAMPLE_FMT_FLTP; avcodec_context->channel_layout = AV_CH_LAYOUT_STEREO; avcodec_context->channels = 2; avcodec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //打开编码器 int ret = avcodec_open2(avcodec_context,avcodec,NULL); if (ret < 0) { //打开失败 return -1; }
2.2 核心编码
需要注意两点:
1.由于PCM格式为S16,AAC格式为FLTP,所以在编码前需要重采样音频,将其格式转换为所需格式。
2.PCM大小为1152,但是AAC的只有1024,所以也需要注意nb_samples的设置。
len = swr_convert(actx, frame->data, frame->nb_samples, data, frame->nb_samples); AVPacket pkt; av_init_packet(&pkt); // 音频编码 ret = avcodec_send_frame(avcodec_context,frame); if (ret != 0) continue; ret = avcodec_receive_packet(avcodec_context,&pkt); if (ret != 0) continue; // 音频封装成aac文件 pkt.stream_index = 0; pkt.pts = 0; pkt.dts = 0; ret = av_interleaved_write_frame(oc,&pkt); cout << "[" << len << "]"; av_packet_unref(&pkt);
三、源码
int main(int argc, char *argv[]) { char infile[] = "out.pcm"; char outfile[] = "out.aac"; av_register_all(); avcodec_register_all(); AVCodec *avcodec = avcodec_find_encoder(AV_CODEC_ID_AAC); if (!codec) { cout << "avcodec_find_encoder error" << endl; return -1; } AVCodecContext *avcodec_context = avcodec_alloc_context3(avcodec); if (!avcodec_context) { cout << "avcodec_alloc_context3 error" << endl; return -1; } avcodec_context->bit_rate = 64000; avcodec_context->sample_rate = 44100; avcodec_context->sample_fmt = AV_SAMPLE_FMT_FLTP; avcodec_context->channel_layout = AV_CH_LAYOUT_STEREO; avcodec_context->channels = 2; avcodec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //打开编码器 int ret = avcodec_open2(avcodec_context,avcodec,NULL); if (ret < 0) { cout << "avcodec_open2 error" << endl; return -1; } cout << "avcodec_open2 success!" << endl; AVFormatContext *oc = NULL; avformat_alloc_output_context2(&oc,NULL,NULL,outfile); if (!oc) { cout << "avformat_alloc_output_context2 error" << endl; return -1; } AVStream *st = avformat_new_stream(oc,NULL); st->codecpar->codec_tag = 0; avcodec_parameters_from_context(st->codecpar,c); ret = avio_open(&oc->pb,outfile,AVIO_FLAG_WRITE); if (ret < 0) { cout << "avio_open error" << endl; return -1; } ret = avformat_write_header(oc,NULL); SwrContext *actx = NULL; actx = swr_alloc_set_opts(actx, avcodec_context->channel_layout, avcodec_context->sample_fmt,avcodec_context->sample_rate, AV_CH_LAYOUT_STEREO,AV_SAMPLE_FMT_S16,44100, 0,0); if (!actx) { cout << "swr_alloc_set_opts error" << endl; return -1; } ret = swr_init(actx); if (ret < 0) { cout << "swr_init error" << endl; return -1; } AVFrame *frame = av_frame_alloc(); frame->format = AV_SAMPLE_FMT_FLTP; frame->channels = 2; frame->channel_layout = AV_CH_LAYOUT_STEREO; frame->nb_samples = 1024; ret = av_frame_get_buffer(frame,0); if (ret < 0) { cout << "av_frame_get_buffer error" << endl; return -1; } int readSize = frame->nb_samples * 2 * 2; char *pcm = new char[readSize]; FILE *fp = fopen(infile,"rb"); for (;;) { int len = fread(pcm,1,readSize,fp); if (len<=0) { break; } const uint8_t *data[1]; data[0] = (uint8_t*)pcm; len = swr_convert(actx, frame->data, frame->nb_samples, data, frame->nb_samples ); if (len <= 0) { break; } AVPacket pkt; av_init_packet(&pkt); //音频编码 ret = avcodec_send_frame(avcodec_context,frame); if (ret != 0) continue; ret = avcodec_receive_packet(avcodec_context,&pkt); if (ret != 0) continue; // 音频封装成aac文件 pkt.stream_index = 0; pkt.pts = 0; pkt.dts = 0; ret = av_interleaved_write_frame(oc,&pkt); cout << "[" << len << "]"; av_packet_unref(&pkt); } AVPacket pkt; av_init_packet(&pkt); ret = avcodec_send_frame(avcodec_context, NULL); cout << "ret1 = " << ret << endl; ret = avcodec_receive_packet(avcodec_context, &pkt); cout << "ret2 = " << ret << endl; pkt.stream_index = 0; pkt.pts = 0; pkt.dts = 0; ret = av_interleaved_write_frame(oc,&pkt); av_packet_unref(&pkt); delete pcm; pcm = NULL; av_write_trailer(oc); avio_close(oc->pb); avformat_free_context(oc); avcodec_close(c); avcodec_free_context(&c); fclose(fp); }
发表评论