YUV數據來源
- 攝像頭直接采集的原始視頻流通常為YUV格式(如YUV420),尤其是安防攝像頭和網絡攝像頭
- 智能手機、平板電腦的攝像頭通過硬件接口
- 視頻會議軟件(如Zoom、騰訊會議)從攝像頭捕獲YUV幀,進行預處理(降噪、美顏)后再編碼
- 專業攝像機或采集卡輸出的高清視頻(如YUV422)用于后期制作,或直播推流前的中間處理
- 自動駕駛、人臉識別等AI模型常直接處理YUV數據
一、調用流程
二、關鍵步驟詳解
1. 初始化組件
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>// 注冊所有編解碼器和封裝格式(新版本可省略)
avformat_network_init(); // 若需網絡功能[citation:2][citation:5]
2. 配置編碼器參數
// 查找H.264編碼器
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);// 設置編碼參數
codec_ctx->width = 1280; // 分辨率
codec_ctx->height = 720;
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; // 輸入YUV格式
codec_ctx->time_base = (AVRational){1, 25}; // 幀率25fps
codec_ctx->bit_rate = 4000000; // 碼率4Mbps
codec_ctx->gop_size = 25; // 關鍵幀間隔[citation:2][citation:6]// 高級參數(可選)
AVDictionary *param = NULL;
av_dict_set(¶m, "preset", "slow", 0); // 編碼質量與速度平衡
av_dict_set(¶m, "tune", "zerolatency", 0); // 低延遲模式[citation:2]// 打開編碼器
avcodec_open2(codec_ctx, codec, ¶m);
3. 創建MP4封裝上下文
AVFormatContext *fmt_ctx = NULL;
avformat_alloc_output_context2(&fmt_ctx, NULL, NULL, "output.mp4");// 添加視頻流
AVStream *stream = avformat_new_stream(fmt_ctx, NULL);
avcodec_parameters_from_context(stream->codecpar, codec_ctx);// 打開輸出文件
avio_open(&fmt_ctx->pb, "output.mp4", AVIO_FLAG_WRITE);
avformat_write_header(fmt_ctx, NULL); // 寫入文件頭[citation:2][citation:5]
4. 處理YUV數據并編碼
AVFrame *frame = av_frame_alloc();
frame->width = codec_ctx->width;
frame->height = codec_ctx->height;
frame->format = codec_ctx->pix_fmt;
av_frame_get_buffer(frame, 32); // 分配幀內存// 讀取YUV文件(示例:YUV420P格式)
FILE *yuv_file = fopen("input.yuv", "rb");
int y_size = frame->width * frame->height;while (fread(frame->data[0], 1, y_size * 3/2, yuv_file) > 0) {frame->pts = frame_count++; // 設置時間戳// 發送幀到編碼器avcodec_send_frame(codec_ctx, frame);// 接收編碼后的包AVPacket *pkt = av_packet_alloc();while (avcodec_receive_packet(codec_ctx, pkt) == 0) {av_packet_rescale_ts(pkt, codec_ctx->time_base, stream->time_base);av_interleaved_write_frame(fmt_ctx, pkt); // 寫入封裝文件av_packet_unref(pkt);}
}
5. 收尾處理
// 沖刷編碼器緩沖區
avcodec_send_frame(codec_ctx, NULL);
while (avcodec_receive_packet(codec_ctx, pkt) == 0) {av_interleaved_write_frame(fmt_ctx, pkt);
}// 寫入文件尾并釋放資源
av_write_trailer(fmt_ctx);
avcodec_free_context(&codec_ctx);
avformat_close_input(&fmt_ctx);