ffmpeg編碼之RGB通過H264編碼並封裝成mp4
阿新 • • 發佈:2019-02-04
原始rgb檔案
h264編碼成功,並封裝成MP4檔案
執行截圖
日誌資訊
實現方式
extern "C" { #include <libavformat/avformat.h> #include <libswscale/swscale.h> } #include <iostream> using namespace std; #pragma comment(lib,"avformat.lib") #pragma comment(lib,"avcodec.lib") #pragma comment(lib,"avutil.lib") #pragma comment(lib,"swscale.lib") int main() { char infile[] = "out.rgb"; char outfile[] = "rgb.mp4"; //註冊封裝,解封裝,格式 av_register_all(); //註冊解碼器 avcodec_register_all(); FILE *fp = fopen(infile,"rb"); if (!fp) { cout << infile << " open failed!" << endl; getchar(); return -1; } int width = 848; int height = 480; int fps = 25; //1 建立編碼器 AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!codec) { cout << " avcodec_find_encoder AV_CODEC_ID_H264 failed!" << endl; getchar(); return -1; } //編碼器上下文 AVCodecContext *c = avcodec_alloc_context3(codec); if (!c) { cout << " avcodec_alloc_context3 failed!" << endl; getchar(); return -1; } //設定視訊編碼相關引數 //位元率 c->bit_rate = 400000000; c->width = width; c->height = height; //把1秒鐘分成fps個單位 c->time_base = { 1,fps }; c->framerate = { fps,1 }; //畫面組大小,就是多少幀出現一個關鍵幀 //GOP 介紹 見 https://blog.csdn.net/xiangjai/article/details/44238005 c->gop_size = 50; c->max_b_frames = 0; c->pix_fmt = AV_PIX_FMT_YUV420P; c->codec_id = AV_CODEC_ID_H264; c->thread_count = 8; //全域性的編碼資訊 c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //開啟編碼器 int ret = avcodec_open2(c,codec,NULL); if (ret < 0) { cout << " avcodec_open2 failed!" << endl; getchar(); return -1; } cout << "avcodec_open2 success!" << endl; //2 create out context AVFormatContext *oc = NULL; avformat_alloc_output_context2(&oc, 0, 0, outfile); //3 add video stream AVStream *st = avformat_new_stream(oc,NULL); st->id = 0; st->codecpar->codec_tag = 0; avcodec_parameters_from_context(st->codecpar,c); cout << "===============================================" << endl; av_dump_format(oc, 0, outfile, 1); cout << "===============================================" << endl; //4 rgb to yuv //改變視訊尺寸 SwsContext *ctx= NULL; ctx = sws_getCachedContext(ctx, width,height,AV_PIX_FMT_BGRA, width,height,AV_PIX_FMT_YUV420P,SWS_BICUBIC, NULL,NULL,NULL); //輸入空間 unsigned char *rgb = new unsigned char[width*height*4]; //輸出空間 AVFrame *yuv = av_frame_alloc(); yuv->format = AV_PIX_FMT_YUV420P; yuv->width = width; yuv->height = height; //分配空間 ret = av_frame_get_buffer(yuv,32); if (ret < 0) { cout << " av_frame_get_buffer failed!" << endl; getchar(); return -1; } //5 write mp4 head ret = avio_open(&oc->pb,outfile,AVIO_FLAG_WRITE); if (ret < 0) { cout << " avio_open failed!" << endl; getchar(); return -1; } ret = avformat_write_header(oc, NULL); if (ret < 0) { cout << " avformat_write_header failed!" << endl; getchar(); return -1; } int p = 0; for (;;) { //size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) //ptr -- 這是指向帶有最小尺寸 size*nmemb 位元組的記憶體塊的指標。 //size -- 這是要讀取的每個元素的大小,以位元組為單位。 //nmemb -- 這是元素的個數,每個元素的大小為 size 位元組。 //stream -- 這是指向 FILE 物件的指標,該 FILE 物件指定了一個輸入流。 int len = fread(rgb,1,width*height*4,fp); if (len<=0) { break; } uint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 }; indata[0] = rgb; int inlinesize[AV_NUM_DATA_POINTERS] = { 0 }; inlinesize[0] = width * 4; int h = sws_scale(ctx,indata,inlinesize,0,height,yuv->data,yuv->linesize); if (h<=0) { break; } //6 encode frame yuv->pts = p; p = p + 3600; //傳送到編碼器 ret = avcodec_send_frame(c,yuv); if (ret != 0) { continue; } AVPacket pkt; av_init_packet(&pkt); //接收編碼結果 ret = avcodec_receive_packet(c,&pkt); if (ret != 0) continue; //將編碼後的幀寫入檔案 av_interleaved_write_frame(oc,&pkt); cout << "<" << pkt.size << ">"; } //寫檔案尾 av_write_trailer(oc); //關閉視訊輸出IO avio_close(oc->pb); //清理封裝輸出上下文 avformat_free_context(oc); //關閉編碼器 avcodec_close(c); //清理編碼器上下文 avcodec_free_context(&c); //清理視訊重取樣上下文 sws_freeContext(ctx); cout << "======================end=========================" << endl; delete rgb; getchar(); return 0; }