本文介紹一個最簡單的基於FFMPEG的視頻編碼器。該編碼器實現了YUV420P的像素資料編碼為H.264的壓縮編碼資料。編碼器代碼十分簡單,但是每一行代碼都很重要,適合好好研究一下。弄清楚了本代碼也就基本弄清楚了FFMPEG的編碼流程。目前我雖然已經調通了程式,但是還是有些地方沒有完全搞明白,需要下一步繼續探究然後補充內容。
本程式使用最新版的類庫(編譯時間為2014.5.6),開發平台為VC2010。所有的配置都已經做好,只需要運行就可以了。
下面直接上代碼:
/* *最簡單的基於FFmpeg的視頻編碼器 *Simplest FFmpeg Video Encoder * *雷霄驊 Lei Xiaohua *leixiaohua1020@126.com *中國傳媒大學/數字電視技術 *Communication University of China / Digital TV Technology *http://blog.csdn.net/leixiaohua1020 * *本程式實現了YUV像素資料編碼為視頻碼流(H264,MPEG2,VP8等等)。 *是最簡單的FFmpeg視頻編碼方面的教程。 *通過學習本例子可以瞭解FFmpeg的編碼流程。 *This software encode YUV420P data to H.264 bitstream. *It's the simplest video encoding software based on FFmpeg. *Suitable for beginner of FFmpeg */#include "stdafx.h"extern "C"{#include "libavcodec\avcodec.h"#include "libavformat\avformat.h"#include "libswscale\swscale.h"};int _tmain(int argc, _TCHAR* argv[]){AVFormatContext* pFormatCtx;AVOutputFormat* fmt;AVStream* video_st;AVCodecContext* pCodecCtx;AVCodec* pCodec;uint8_t* picture_buf;AVFrame* picture;int size;FILE *in_file = fopen("src01_480x272.yuv", "rb");//視頻YUV源檔案 int in_w=480,in_h=272;//寬高int framenum=50;const char* out_file = "src01.h264";//輸出檔案路徑av_register_all();//方法1.組合使用幾個函數pFormatCtx = avformat_alloc_context();//猜格式fmt = av_guess_format(NULL, out_file, NULL);pFormatCtx->oformat = fmt;//方法2.更加自動化一些//avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);//fmt = pFormatCtx->oformat;//注意輸出路徑if (avio_open(&pFormatCtx->pb,out_file, AVIO_FLAG_READ_WRITE) < 0){printf("輸出檔案開啟失敗");return -1;}video_st = av_new_stream(pFormatCtx, 0);if (video_st==NULL){return -1;}pCodecCtx = video_st->codec;pCodecCtx->codec_id = fmt->video_codec;pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;pCodecCtx->pix_fmt = PIX_FMT_YUV420P;pCodecCtx->width = in_w; pCodecCtx->height = in_h;pCodecCtx->time_base.num = 1; pCodecCtx->time_base.den = 25; pCodecCtx->bit_rate = 400000; pCodecCtx->gop_size=250;//H264//pCodecCtx->me_range = 16;//pCodecCtx->max_qdiff = 4;pCodecCtx->qmin = 10;pCodecCtx->qmax = 51;//pCodecCtx->qcompress = 0.6;//輸出格式資訊av_dump_format(pFormatCtx, 0, out_file, 1);pCodec = avcodec_find_encoder(pCodecCtx->codec_id);if (!pCodec){printf("沒有找到合適的編碼器!\n");return -1;}if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0){printf("編碼器開啟失敗!\n");return -1;}picture = avcodec_alloc_frame();size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);picture_buf = (uint8_t *)av_malloc(size);avpicture_fill((AVPicture *)picture, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);//寫檔案頭avformat_write_header(pFormatCtx,NULL);AVPacket pkt;int y_size = pCodecCtx->width * pCodecCtx->height;av_new_packet(&pkt,y_size*3);for (int i=0; i<framenum; i++){//讀入YUVif (fread(picture_buf, 1, y_size*3/2, in_file) < 0){printf("檔案讀取錯誤\n");return -1;}else if(feof(in_file)){break;}picture->data[0] = picture_buf; // 亮度Ypicture->data[1] = picture_buf+ y_size; // U picture->data[2] = picture_buf+ y_size*5/4; // V//PTSpicture->pts=i;int got_picture=0;//編碼int ret = avcodec_encode_video2(pCodecCtx, &pkt,picture, &got_picture);if(ret < 0){printf("編碼錯誤!\n");return -1;}if (got_picture==1){printf("編碼成功第%d幀!\n",i);pkt.stream_index = video_st->index;ret = av_write_frame(pFormatCtx, &pkt);av_free_packet(&pkt);}}//寫檔案尾av_write_trailer(pFormatCtx);//清理if (video_st){avcodec_close(video_st->codec);av_free(picture);av_free(picture_buf);}avio_close(pFormatCtx->pb);avformat_free_context(pFormatCtx);fclose(in_file);return 0;}
軟體運行(受限於檔案體積,原始YUV幀數很少):
編碼前的YUV序列:
編碼後的H.264碼流:
:
http://download.csdn.net/detail/leixiaohua1020/7324115
SourceForge項目地址:
https://sourceforge.net/projects/simplestffmpegvideoencoder/