利用ffmpeg將H264流 解碼為RGB
阿新 • • 發佈:2019-01-21
利用H264解碼分為幾個步驟:
注意一點在新增標頭檔案的時候要新增extern "C",不然會出現錯誤
- extern"C"
- {
- #include <avcodec.h>
- #include <avformat.h>
- #include <avutil.h>
- #include <swscale.h>
- };
這裡申明瞭幾個全域性變數
- AVCodec *pCodec = NULL;
- AVCodecContext *pCodecCtx = NULL;
- SwsContext *img_convert_ctx = NULL;
- AVFrame *pFrame = NULL;
- AVFrame *pFrameRGB = NULL;
1. 初始化
- int H264_Init(void)
- {
- /* must be called before using avcodec lib*/
- avcodec_init();
- /* register all the codecs */
- avcodec_register_all();
- /* find the h264 video decoder */
- pCodec = avcodec_find_decoder(CODEC_ID_H264);
- if (!pCodec) {
- fprintf(stderr, "codec not found\n"
- }
- pCodecCtx = avcodec_alloc_context();
- /* open the coderc */
- if (avcodec_open(pCodecCtx, pCodec) < 0) {
- fprintf(stderr, "could not open codec\n");
- }
- // Allocate video frame
- pFrame = avcodec_alloc_frame();
- if(pFrame == NULL)
- return -1;
- // Allocate an AVFrame structure
- pFrameRGB=avcodec_alloc_frame();
- if(pFrameRGB == NULL)
- return -1;
- return 0;
- }
在最早使用的時候沒有使用全域性變數,初始化中也就只有init和regisger這兩個函式,而這樣做的下場是,非關鍵幀全部無法解碼,只有關鍵幀才有辦法解碼。
2. 解碼
解碼的時候avcodec_decode_video函式是進行解碼操作,在外部定義outputbuf的大小時,pixes*3,outsize是返回的outputbuf的size,值也是pixes*3。
在解碼的時候這幾句話的意義是將YUV420P的資料倒置。在原先使用中,發現解出來的影象居然是中心旋轉圖,後面在網上找了些辦法,覺得這個比較實用。解碼實時是很重要的,影象轉化完之後也可以講RGB圖再次轉化,那樣也能成為一個正的圖,但是那樣效率就明顯低了。
- pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);
- pFrame->linesize[0] *= -1;
- pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;
- pFrame->linesize[1] *= -1;
- pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;
- pFrame->linesize[2] *= -1;
- int H264_2_RGB(unsigned char *inputbuf, int frame_size, unsigned char *outputbuf, unsigned int*outsize)
- {
- int decode_size;
- int numBytes;
- int av_result;
- uint8_t *buffer = NULL;
- printf("Video decoding\n");
- av_result = avcodec_decode_video(pCodecCtx, pFrame, &decode_size, inputbuf, frame_size);
- if (av_result < 0)
- {
- fprintf(stderr, "decode failed: inputbuf = 0x%x , input_framesize = %d\n", inputbuf, frame_size);
- return -1;
- }
- // Determine required buffer size and allocate buffer
- numBytes=avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width,
- pCodecCtx->height);
- buffer = (uint8_t*)malloc(numBytes * sizeof(uint8_t));
- // Assign appropriate parts of buffer to image planes in pFrameRGB
- avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24,
- pCodecCtx->width, pCodecCtx->height);
- img_convert_ctx = sws_getCachedContext(img_convert_ctx,pCodecCtx->width,pCodecCtx->height,
- //PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,
- pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,PIX_FMT_RGB24 ,
- SWS_X ,NULL,NULL,NULL) ;
- if (img_convert_ctx == NULL)
- {
- printf("can't init convert context!\n") ;
- return -1;
- }
- pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);
- pFrame->linesize[0] *= -1;
- pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;
- pFrame->linesize[1] *= -1;
- pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;
- pFrame->linesize[2] *= -1;
- sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,
- 0, 0 - pCodecCtx->width, pFrameRGB->data, pFrameRGB->linesize);
- if (decode_size)
- {
- *outsize = pCodecCtx->width * pCodecCtx->height * 3;
- memcpy(outputbuf, pFrameRGB->data[0], *outsize);
- }
- free(buffer);
- return 0;
- }
//解碼yuv 修改 PIX_FMT_YUV420P memcpy(outputbuf, pFrameRGB->data[2], 720*576/4); memcpy(outputbuf, pFrameRGB->data[1], 720*576/4); memcpy(outputbuf, pFrameRGB->data[0], 720*576);
3. 釋放資源
資源的回收。
- void H264_Release(void)
- {
- avcodec_close(pCodecCtx);
- av_free(pCodecCtx);
- av_free(pFrame);
- av_free(pFrameRGB);
- }