最簡單的基于FFmpeg的編碼器-純凈版(不包含libavformat)
來源:程序員人生 發布時間:2015-01-04 09:06:54 閱讀次數:4251次
=====================================================
最簡單的基于FFmpeg的視頻編碼器文章列表:
最簡單的基于FFMPEG的視頻編碼器(YUV編碼為H.264)
最簡單的基于FFmpeg的視頻編碼器-更新版(YUV編碼為HEVC(H.265))
最簡單的基于FFmpeg的編碼器-純凈版(不包括libavformat)
=====================================================
本文記錄1個更加“純凈”的基于FFmpeg的視頻編碼器。此前記錄過1個基于FFmpeg的視頻編碼器:
《最簡單的基于FFmpeg的視頻編碼器-更新版(YUV編碼為HEVC(H.265))》
這個視頻編碼器調用了FFmpeg中的libavformat和libavcodec兩個庫完成了視頻編碼工作。但是這不是1個“純凈”的編碼器。上述兩個庫中libavformat完成封裝格式處理,而libavcodec完成編碼工作。1個“純凈”的編碼器,理論上說只需要使用libavcodec就足夠了,其實不需要使用libavformat。本文記錄的編碼器就是這樣的1個“純凈”的編碼器,它僅僅通過調用libavcodec將YUV數據編碼為H.264/HEVC等格式的緊縮視頻碼流。
流程圖
僅使用libavcodec(不使用libavformat)編碼視頻的流程以下圖所示。

流程圖中關鍵函數的作用以下所列:
avcodec_register_all():注冊所有的編解碼器。
avcodec_find_encoder():查找編碼器。
avcodec_alloc_context3():為AVCodecContext分配內存。
avcodec_open2():打開編碼器。
avcodec_encode_video2():編碼1幀數據。
兩個存儲數據的結構體以下所列:
AVFrame:存儲1幀未編碼的像素數據。
AVPacket:存儲1幀緊縮編碼數據。
對照
簡單記錄1下這個只使用libavcodec的“純凈版”視頻編碼器和使用libavcodec+libavformat的視頻編碼器的不同。
PS:使用libavcodec+libavformat的編碼器參考文章 《最簡單的基于FFmpeg的視頻編碼器-更新版(YUV編碼為HEVC(H.265))》
(1)
以下與libavformat相干的函數在“純凈版”視頻編碼器中都不存在。
av_register_all():注冊所有的編解碼器,復用/解復用器等等組件。其中調用了avcodec_register_all()注冊所有編解碼器相干的組件。
avformat_alloc_context():創建AVFormatContext結構體。
avformat_alloc_output_context2():初始化1個輸出流。
avio_open():打開輸出文件。
avformat_new_stream():創建AVStream結構體。avformat_new_stream()中會調用avcodec_alloc_context3()創建AVCodecContext結構體。
avformat_write_header():寫文件頭。
av_write_frame():寫編碼后的文件幀。
av_write_trailer():寫文件尾。
(2)
新增了以下幾個函數
avcodec_register_all():只注冊編解碼器有關的組件。avcodec_alloc_context3():創建AVCodecContext結構體。
可以看出,相比于“完全”的編碼器,這個純凈的編碼器函數調用更加簡單,功能相對少1些,相對來講更加的“輕量”。
源代碼
/**
* 最簡單的基于FFmpeg的視頻編碼器(純凈版)
* Simplest FFmpeg Video Encoder Pure
*
* 雷霄驊 Lei Xiaohua
* leixiaohua1020@126.com
* 中國傳媒大學/數字電視技術
* Communication University of China / Digital TV Technology
* http://blog.csdn.net/leixiaohua1020
*
* 本程序實現了YUV像素數據編碼為視頻碼流(H264,MPEG2,VP8等等)。
* 它僅僅使用了libavcodec(而沒有使用libavformat)。
* 是最簡單的FFmpeg視頻編碼方面的教程。
* 通過學習本例子可以了解FFmpeg的編碼流程。
* This software encode YUV420P data to video bitstream
* (Such as H.264, H.265, VP8, MPEG2 etc).
* It only uses libavcodec to encode video (without libavformat)
* It's the simplest video encoding software based on FFmpeg.
* Suitable for beginner of FFmpeg
*/
#include <stdio.h>
extern "C"
{
#include "libavutilopt.h"
#include "libavcodecavcodec.h"
#include "libavutilimgutils.h"
};
//test different codec
#define TEST_H264 0
#define TEST_HEVC 1
int main(int argc, char* argv[])
{
AVCodec *pCodec;
AVCodecContext *pCodecCtx= NULL;
int i, ret, x, y, got_output;
FILE *fp_in;
FILE *fp_out;
AVFrame *pFrame;
AVPacket pkt;
int y_size;
int framecnt=0;
char filename_in[]="../ds_480x272.yuv";
#if TEST_HEVC
AVCodecID codec_id=AV_CODEC_ID_HEVC;
char filename_out[]="ds.hevc";
#else
AVCodecID codec_id=AV_CODEC_ID_H264;
char filename_out[]="ds.h264";
#endif
int in_w=480,in_h=272;
int framenum=100;
avcodec_register_all();
pCodec = avcodec_find_encoder(codec_id);
if (!pCodec) {
printf("Codec not found
");
return ⑴;
}
pCodecCtx = avcodec_alloc_context3(pCodec);
if (!pCodecCtx) {
printf("Could not allocate video codec context
");
return ⑴;
}
pCodecCtx->bit_rate = 400000;
pCodecCtx->width = in_w;
pCodecCtx->height = in_h;
pCodecCtx->time_base.num=1;
pCodecCtx->time_base.den=25;
pCodecCtx->gop_size = 10;
pCodecCtx->max_b_frames = 1;
pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
if (codec_id == AV_CODEC_ID_H264)
av_opt_set(pCodecCtx->priv_data, "preset", "slow", 0);
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
printf("Could not open codec
");
return ⑴;
}
pFrame = av_frame_alloc();
if (!pFrame) {
printf("Could not allocate video frame
");
return ⑴;
}
pFrame->format = pCodecCtx->pix_fmt;
pFrame->width = pCodecCtx->width;
pFrame->height = pCodecCtx->height;
ret = av_image_alloc(pFrame->data, pFrame->linesize, pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, 16);
if (ret < 0) {
printf("Could not allocate raw picture buffer
");
return ⑴;
}
//Input raw data
fp_in = fopen(filename_in, "rb");
if (!fp_in) {
printf("Could not open %s
", filename_in);
return ⑴;
}
//Output bitstream
fp_out = fopen(filename_out, "wb");
if (!fp_out) {
printf("Could not open %s
", filename_out);
return ⑴;
}
y_size = pCodecCtx->width * pCodecCtx->height;
//Encode
for (i = 0; i < framenum; i++) {
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
//Read raw YUV data
if (fread(pFrame->data[0],1,y_size,fp_in)< 0|| // Y
fread(pFrame->data[1],1,y_size/4,fp_in)< 0|| // U
fread(pFrame->data[2],1,y_size/4,fp_in)< 0){ // V
return ⑴;
}else if(feof(fp_in)){
break;
}
pFrame->pts = i;
/* encode the image */
ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_output);
if (ret < 0) {
printf("Error encoding frame
");
return ⑴;
}
if (got_output) {
printf("Succeed to encode frame: %5d size:%5d
",framecnt,pkt.size);
framecnt++;
fwrite(pkt.data, 1, pkt.size, fp_out);
av_free_packet(&pkt);
}
}
//Flush Encoder
for (got_output = 1; got_output; i++) {
ret = avcodec_encode_video2(pCodecCtx, &pkt, NULL, &got_output);
if (ret < 0) {
printf("Error encoding frame
");
return ⑴;
}
if (got_output) {
printf("Flush Encoder: Succeed to encode 1 frame! size:%5d
",pkt.size);
fwrite(pkt.data, 1, pkt.size, fp_out);
av_free_packet(&pkt);
}
}
fclose(fp_out);
avcodec_close(pCodecCtx);
av_free(pCodecCtx);
av_freep(&pFrame->data[0]);
av_frame_free(&pFrame);
return 0;
}
運行結果
通過設定定義在程序開始的宏,肯定需要使用的編碼器。
//test different codec
#define TEST_H264 0
#define TEST_HEVC 1
當TEST_H264設置為1的時候,編碼H.264文件“ds.h264”。
當TEST_HEVC設置為1的時候,解碼HEVC文件“ds.hevc”。
輸入文件是“ds_480x272.yuv”。
程序運行的截圖以下所示。

輸入的YUV文件以下圖所示。

輸出的HEVC文件以下圖所示。

下載
Simplest ffmpeg encoder pure工程被作為子工程添加到了simplest ffmpeg video encoder工程中。新版的simplest ffmpeg video encoder的信息以下。
Simplest ffmpeg video encoderSourceForge主頁:https://sourceforge.net/projects/simplestffmpegvideoencoder/
CSDN下載地址:http://download.csdn.net/detail/leixiaohua1020/8322003
本程序實現了YUV像素數據編碼為視頻碼流(H.265,H264,MPEG2,VP8等等)。
是最簡單的FFmpeg視頻編碼方面的教程。
它包括以下兩個子項目:
simplest_ffmpeg_video_encoder:最簡單的基于FFmpeg的視頻編碼器。使用libavcodec和libavformat編碼并且封裝視頻。
simplest_ffmpeg_video_encoder_pure:最簡單的基于FFmpeg的視頻編碼器-純凈版。僅使用libavcodec編碼視頻,不使用libavformat。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈