1. 程式人生 > >FFmpeg 264編碼示例

FFmpeg 264編碼示例

示例程式碼:

encoder_work::encoder_work()
{
	mWidth = 0;
	mHeight = 0;
	mFPS = 0;
	mYSize = 0;
	mUVSize = 0;
	mPTS = 0;
	mFmtCtx = NULL;
	mEncCtx = NULL;
	mYUVFrm = NULL;
	mEncoder = NULL;
}


int encoder_work::init(int w, int h, int fps, int bit_rate, char *outfile_name)
{
	printf("encoder work init========>\n"
); uninit(); mWidth = w; mHeight = h; mFPS = fps; mYSize = w*h; mUVSize = mYSize / 4; //register file package like mp4 and all others av_register_all(); //register all codecs avcodec_register_all(); //1 create encoder mEncoder = avcodec_find_encoder(AV_CODEC_ID_H264); if (!mEncoder) { cout <<
" avcodec_find_encoder AV_CODEC_ID_H264 failed!" << endl; return -1; } //get encoder contex mEncCtx = avcodec_alloc_context3(mEncoder); if (!mEncCtx) { cout << " avcodec_alloc_context3 for encoder contx failed!" << endl; return -1; } //set encoder params //bit rate mEncCtx->
bit_rate = bit_rate; mEncCtx->width = mWidth; mEncCtx->height = mHeight; mEncCtx->time_base = { 1,mFPS }; //set gop size, in another way I frame gap mEncCtx->gop_size = 50; mEncCtx->max_b_frames = 0; mEncCtx->pix_fmt = AV_PIX_FMT_YUV420P; mEncCtx->codec_id = AV_CODEC_ID_H264; mEncCtx->thread_count = 4; mEncCtx->qmin = 10; mEncCtx->qmax = 51; mEncCtx->qcompress = 0.6; //av_opt_set(mEncCtx->priv_data, "preset", "ultrafast", 0); av_opt_set(mEncCtx->priv_data, "tune", "zerolatency", 0); //global header info mEncCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //open encoder int ret = avcodec_open2(mEncCtx,mEncoder,NULL); if (ret < 0) { cout << " avcodec_open2 encoder failed!" << endl; return -1; } cout << "avcodec_open2 encoder success!" << endl; //2 create out context avformat_alloc_output_context2(&mFmtCtx, 0, 0, outfile_name); //3 add video stream mOutStm = avformat_new_stream(mFmtCtx,NULL); mOutStm->id = 0; mOutStm->codecpar->codec_tag = 0; avcodec_parameters_from_context(mOutStm->codecpar,mEncCtx); cout << "===============================================" << endl; av_dump_format(mFmtCtx, 0, outfile_name, 1); cout << "===============================================" << endl; //alloc output yuv frame mYUVFrm = av_frame_alloc(); mYUVFrm->format = AV_PIX_FMT_YUV420P; mYUVFrm->width = mWidth; mYUVFrm->height = mHeight; //alloc frame buffer ret = av_frame_get_buffer(mYUVFrm,32); if (ret < 0) { av_frame_free(&mYUVFrm); mYUVFrm = NULL; cout << " av_frame_get_buffer failed!" << endl; return -1; } //5 write mp4 head ret = avio_open(&mFmtCtx->pb,outfile_name,AVIO_FLAG_WRITE); if (ret < 0) { cout << " avio_open failed!" << endl; return -1; } ret = avformat_write_header(mFmtCtx, NULL); if (ret < 0) { cout << " avformat_write_header failed!" << endl; return -1; } } int encoder_work::uninit() { printf("encoder_work uninit-----\n"); if(mFmtCtx) { //wirte file trailer av_write_trailer(mFmtCtx); //close file IO avio_close(mFmtCtx->pb); //clean context avformat_free_context(mFmtCtx); mFmtCtx = NULL; } if(mEncCtx) { //close encoder avcodec_close(mEncCtx); //clean encoder contex avcodec_free_context(&mEncCtx); mEncCtx = NULL; } if(mYUVFrm) { av_frame_free(&mYUVFrm); mYUVFrm = NULL; } mWidth = 0; mHeight = 0; mFPS = 0; mYSize = 0; mUVSize = 0; mPTS = 0; return 0; } int encoder_work::process(cv::Mat &rgb) { cv::Mat yuv; cv::cvtColor(rgb, yuv, cv::COLOR_BGR2YUV_I420); return process(yuv.data); } int encoder_work::process(unsigned char *yuvData) { if(!mYUVFrm) { printf("not ready env\n"); return -1; } memcpy(mYUVFrm->data[0], yuvData, mYSize); memcpy(mYUVFrm->data[1], yuvData+mYSize, mUVSize); memcpy(mYUVFrm->data[2], yuvData+mYSize+mUVSize, mUVSize); mYUVFrm->pts = mPTS; mPTS = mPTS + 4000; //mPTS = mPTS + 1000000; //send to encoder int ret = avcodec_send_frame(mEncCtx, mYUVFrm); if (ret != 0) { char err[64] = {0}; av_strerror(ret, err, 64); printf("encoder send frame %d err:%s\n",mPTS-4000, err); return -1; } AVPacket pkt; av_init_packet(&pkt); //receive from encoder //note that frame will not be received immediately ret = avcodec_receive_packet(mEncCtx,&pkt); if (ret != 0) { printf("encoder recieve frame %d err\n",mPTS-4000); return -1; } //write encoded frame to file av_interleaved_write_frame(mFmtCtx,&pkt); av_free_packet(&pkt); return 0; } int encoder_work::flushOut() { //as frames will be hysteresis, we need flush all remained frames AVPacket pkt; av_init_packet(&pkt); int ret = 0; while(ret >= 0) { //flush out rest frames, send NULL frame data avcodec_send_frame(mEncCtx, NULL); //receive frame from encoder ret = avcodec_receive_packet(mEncCtx,&pkt); if (ret != 0) { printf("encoder recieve frame %d err\n",mPTS-4000); break; } //wirte encoded frame to file av_interleaved_write_frame(mFmtCtx,&pkt); av_free_packet(&pkt); } return 0; }

標頭檔案定義

class encoder_work
{
public:
	encoder_work();
	~encoder_work() { uninit(); }

	int init(int w, int h, int fps, int bit_rate, char *outfile_name);
	int uninit();
	int process(unsigned char *yuvData);
	int process(cv::Mat &rgb);
	int flushOut();

private:
	int mWidth;
	int mHeight;
	int mFPS;
	int mYSize;
	int mUVSize;
	int mPTS;
	AVCodec *mEncoder;
	AVCodecContext *mEncCtx;
	AVFormatContext *mFmtCtx;
	AVStream *mOutStm;
	AVFrame *mYUVFrm;
};