视频编码流程

- avcodec_find_encoder:首先,通过指定的编码器名称(如H.264、MPEG-4等)找到对应的编码器。
- avcodec_alloc_context3:为找到的编码器分配一个上下文结构,这个结构包含了编码器所需的各种参数和状态信息。
- 设置编码上下文参数:配置编码器上下文的参数,包括分辨率、帧率、比特率等。
- avcodec_open2:打开编码器,准备开始编码工作。
- av_packet_alloc:分配一个AVPacket结构,用于存储编码后的数据包。
- av_frame_alloc:分配一个AVFrame结构,用于存储原始视频帧的数据。
- 设置Frame参数:配置AVFrame结构,包括设置像素格式、宽度、高度等参数。
- av_frame_get_buffer:为AVFrame分配缓冲区,用于存储视频帧的数据。
- 读文件:从输入源读取视频帧数据。如果读取成功,则继续处理;如果读取失败,则跳转到flush_encode步骤。
- avcodec_send_frame:将AVFrame发送给编码器进行编码。
- avcodec_receive_packet:从编码器接收编码后的数据包。
- 写文件:将编码后的数据包写入输出文件。
- flush_encode:当读取文件失败时,调用flush_encode函数清理编码器中的剩余数据。
- 释放资源:释放之前分配的所有资源,包括AVFrame、AVPacket和编码器上下文。
#include<QDebug>
extern "C"{
#include<libavcodec/avcodec.h>
}const char* inFileName = "D:\\output.yuv";
const char* outFileName = "output.h264";
int encode(AVCodecContext* codecContext, AVPacket* packet, AVFrame* frame, FILE* outFile) {int ret = avcodec_send_frame(codecContext, frame);if (ret < 0) {qDebug() << "avcodec_send_frame failed";return -8; }while (ret == 0) {ret = avcodec_receive_packet(codecContext, packet);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {return 0; }else if (ret < 0) {qDebug() << "avcodec_receive_packet failed";return -9; }if (ret == 0) {fwrite(packet->data, 1, packet->size, outFile);}}return 0;
}int main(){int ret = 0;const AVCodec* codec = nullptr;AVCodecContext* codecContext = nullptr;AVPacket* packet = nullptr;AVFrame* frame = nullptr;FILE* inFile = nullptr;FILE* outFile = nullptr;codec = avcodec_find_encoder(AV_CODEC_ID_H264);if(!codec){qDebug() << "avcodec_find_encoder failed";return -1;}codecContext = avcodec_alloc_context3(codec);if(!codecContext){qDebug() << "avcodec_alloc_context3 failed";return -2;}codecContext->width = 1280; codecContext->height = 720; codecContext->time_base = AVRational{1, 25}; codecContext->pix_fmt = AV_PIX_FMT_YUV420P; codecContext->framerate = AVRational{25, 1}; ret = avcodec_open2(codecContext, codec, NULL);if(ret != 0){qDebug() << "avcodec_open2 failed";return -3;}packet = av_packet_alloc();if(!packet){qDebug() << "avcodec_open2 failed";return -4;}frame = av_frame_alloc();if(!frame){qDebug() << "av_frame_alloc failed";return -5;}frame->width = 1280;frame->height = 720;frame->format = AV_PIX_FMT_YUV420P;ret = av_frame_get_buffer(frame, 0);if (ret < 0) { qDebug() << "av_frame_get_buffer failed, error:" << ret;return -6;}inFile = fopen(inFileName, "rb");if(inFile == nullptr){qDebug() << "open infile failed";return -7;}outFile = fopen(outFileName, "wb");if(outFile == nullptr){qDebug() << "open outFileName failed";return -7;}while(!feof(inFile)){ret = av_frame_is_writable(frame);if(ret < 0){ret = av_frame_make_writable(frame);}fread(frame->data[0], 1, frame->width * frame->height, inFile);fread(frame->data[1], 1, frame->width * frame->height / 4, inFile);fread(frame->data[2], 1, frame->width * frame->height / 4, inFile);encode(codecContext, packet, frame, outFile);}encode(codecContext, packet, nullptr, outFile); qDebug()<<"编码完成";av_packet_free(&packet);av_frame_free(&frame);avcodec_free_context(&codecContext);fclose(inFile);fclose(outFile);return 0;
}
音频编码实战

一、初始化阶段
- avcodec_find_encoder
查找合适的音频编码器(如 AAC、MP3)。 - avcodec_alloc_context3
分配编码器上下文。 - 设置编码器参数
如采样率、通道数、比特率等。 - avcodec_open2
打开编码器。 - avformat_alloc_output_context2
创建输出格式上下文。 - avformat_new_stream
新建输出音频流。 - avio_open
打开输出文件。 - avformat_write_header
写入文件头信息。 - swr_init
初始化音频重采样(如果需要转换采样格式或通道布局)。
二、编码循环阶段
- av_frame_get_buffer
获取一个音频帧缓冲区用于填充数据。 - 读取文件
判断是否还有音频数据需要编码。 - 如果有(true):
- avcodec_send_frame:送入音频帧。
- avcodec_receive_packet:从编码器接收压缩数据。
- av_interleaved_write_frame:将编码后数据写入输出文件。
- 如果没有(false):
- flush_encode:刷新编码器内部缓存(送入空帧)。
- av_write_trailer:写入文件尾。
- 释放资源:关闭文件、释放上下文、帧、包等资源。
#include <QDebug>
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
}int main(){char inputfile[] = "D:\\output.pcm";char outputfile[] = "audio.aac";const AVCodec* avCodec = avcodec_find_encoder(AV_CODEC_ID_AAC);if(!avCodec){qDebug() << "avcodec_find_encoder failed";return -1;}AVCodecContext* avCodecContext = avcodec_alloc_context3(avCodec);if(!avCodecContext){qDebug() << "avcodec_alloc_context3 failed";return -1;}int ret=0;avCodecContext->sample_rate = 44100; avCodecContext->channels = 2; avCodecContext->sample_fmt = AV_SAMPLE_FMT_FLTP; avCodecContext->bit_rate = 64000; avCodecContext->channel_layout = AV_CH_LAYOUT_STEREO; ret = avcodec_open2(avCodecContext, avCodec,NULL);if(ret<0){qDebug() << "avcodec_open2 failed";return -1;}AVFormatContext* avFormatContext = NULL;avformat_alloc_output_context2(&avFormatContext, NULL, NULL, outputfile);if(!avFormatContext){qDebug() << "avformat_alloc_output_context2 failed";return -1;}AVStream* st = avformat_new_stream(avFormatContext, NULL);st->codecpar->codec_tag = 0;avcodec_parameters_from_context(st->codecpar, avCodecContext);ret = avio_open(&avFormatContext->pb, outputfile, AVIO_FLAG_WRITE);if(ret<0){qDebug() << "avio_open failed";return -1;}avformat_write_header(avFormatContext, NULL);SwrContext* swrContext = NULL;swrContext = swr_alloc_set_opts(swrContext, avCodecContext->channel_layout, avCodecContext->sample_fmt, avCodecContext->sample_rate,AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, 44100,0, 0);if(!swrContext){qDebug() << "swr_alloc_set_opts failed";return -1;}ret = swr_init(swrContext);if(ret<0){qDebug() << "swr_init failed";return -1;}AVFrame* avFrame = av_frame_alloc();avFrame->format = AV_SAMPLE_FMT_FLTP;avFrame->channels=2;avFrame->channel_layout = AV_CH_LAYOUT_STEREO;avFrame->nb_samples=1024;ret = av_frame_get_buffer(avFrame, 0);if(ret<0){qDebug() << "av_frame_get_buffer failed";return -1;}int readSize = avFrame->nb_samples*2*2; char* pcms = new char[readSize]; FILE* fp = fopen(inputfile, "rb");for(;;){AVPacket pkt;av_init_packet(&pkt);int len = fread(pcms,1,readSize, fp);if(len <=0){break;}else{const uint8_t* data[1];data[0] = (uint8_t*)pcms;len = swr_convert(swrContext, avFrame->data, avFrame->nb_samples, data, avFrame->nb_samples);if(len <=0){qDebug() << "swr_convert failed";break;}ret = avcodec_send_frame(avCodecContext, avFrame);if(ret < 0){qDebug() << "avcodec_send_frame failed";continue;}ret = avcodec_receive_packet(avCodecContext, &pkt);if(ret == 0){av_interleaved_write_frame(avFormatContext, &pkt);}}}av_write_trailer(avFormatContext);fclose(fp);avio_close(avFormatContext->pb);avcodec_close(avCodecContext);avcodec_free_context(&avCodecContext);avformat_free_context(avFormatContext);return 0;
}