视频编码流程

- 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;
}