1. 程式人生 > >利用ffmpeg將H264流 解碼為RGB

利用ffmpeg將H264流 解碼為RGB

利用H264解碼分為幾個步驟:

注意一點在新增標頭檔案的時候要新增extern "C",不然會出現錯誤

  1. extern"C"
  2. {  
  3. #include <avcodec.h>
  4. #include <avformat.h>
  5. #include <avutil.h>
  6. #include <swscale.h>
  7. };  

這裡申明瞭幾個全域性變數

  1. AVCodec         *pCodec = NULL;  
  2. AVCodecContext  *pCodecCtx = NULL;  
  3. SwsContext      *img_convert_ctx = NULL;  
  4. AVFrame         *pFrame = NULL;  
  5. AVFrame         *pFrameRGB = NULL;  

1. 初始化

  1. int H264_Init(void)  
  2. {  
  3.     /* must be called before using avcodec lib*/
  4.     avcodec_init();  
  5.     /* register all the codecs */
  6.     avcodec_register_all();  
  7.     /* find the h264 video decoder */
  8.     pCodec = avcodec_find_decoder(CODEC_ID_H264);  
  9.     if (!pCodec) {  
  10.         fprintf(stderr, "codec not found\n"
    );  
  11.     }  
  12.     pCodecCtx = avcodec_alloc_context();  
  13.     /* open the coderc */
  14.     if (avcodec_open(pCodecCtx, pCodec) < 0) {  
  15.         fprintf(stderr, "could not open codec\n");  
  16.     }  
  17.     // Allocate video frame
  18.     pFrame = avcodec_alloc_frame();  
  19.     if(pFrame == NULL)  
  20.         return -1;  
  21.     // Allocate an AVFrame structure
  22.     pFrameRGB=avcodec_alloc_frame();  
  23.     if(pFrameRGB == NULL)  
  24.         return -1;  
  25.     return 0;  
  26. }  

在最早使用的時候沒有使用全域性變數,初始化中也就只有init和regisger這兩個函式,而這樣做的下場是,非關鍵幀全部無法解碼,只有關鍵幀才有辦法解碼。

2. 解碼

解碼的時候avcodec_decode_video函式是進行解碼操作,在外部定義outputbuf的大小時,pixes*3,outsize是返回的outputbuf的size,值也是pixes*3。

在解碼的時候這幾句話的意義是將YUV420P的資料倒置。在原先使用中,發現解出來的影象居然是中心旋轉圖,後面在網上找了些辦法,覺得這個比較實用。解碼實時是很重要的,影象轉化完之後也可以講RGB圖再次轉化,那樣也能成為一個正的圖,但是那樣效率就明顯低了。

  1. pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);  
  2. pFrame->linesize[0] *= -1;  
  3. pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;  
  4. pFrame->linesize[1] *= -1;  
  5. pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;  
  6. pFrame->linesize[2] *= -1;  
  1. int H264_2_RGB(unsigned char *inputbuf, int frame_size, unsigned char *outputbuf, unsigned int*outsize)  
  2. {  
  3.     int             decode_size;  
  4.     int             numBytes;  
  5.     int             av_result;  
  6.     uint8_t         *buffer = NULL;  
  7.     printf("Video decoding\n");  
  8.     av_result = avcodec_decode_video(pCodecCtx, pFrame, &decode_size, inputbuf, frame_size);  
  9.     if (av_result < 0)  
  10.     {  
  11.         fprintf(stderr, "decode failed: inputbuf = 0x%x , input_framesize = %d\n", inputbuf, frame_size);  
  12.         return -1;  
  13.     }  
  14.     // Determine required buffer size and allocate buffer
  15.     numBytes=avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width,  
  16.         pCodecCtx->height);  
  17.     buffer = (uint8_t*)malloc(numBytes * sizeof(uint8_t));  
  18.     // Assign appropriate parts of buffer to image planes in pFrameRGB
  19.     avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24,  
  20.         pCodecCtx->width, pCodecCtx->height);  
  21.     img_convert_ctx = sws_getCachedContext(img_convert_ctx,pCodecCtx->width,pCodecCtx->height,  
  22.         //PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,
  23.         pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,PIX_FMT_RGB24 ,  
  24.         SWS_X ,NULL,NULL,NULL) ;  
  25.     if (img_convert_ctx == NULL)   
  26.     {  
  27.         printf("can't init convert context!\n") ;  
  28.         return -1;  
  29.     }  
  30.     pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);  
  31.     pFrame->linesize[0] *= -1;  
  32.     pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;  
  33.     pFrame->linesize[1] *= -1;  
  34.     pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;  
  35.     pFrame->linesize[2] *= -1;  
  36.     sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,  
  37.         0, 0 - pCodecCtx->width, pFrameRGB->data, pFrameRGB->linesize);  
  38.     if (decode_size)  
  39.     {  
  40.         *outsize = pCodecCtx->width * pCodecCtx->height * 3;  
  41.         memcpy(outputbuf, pFrameRGB->data[0], *outsize);  
  42.     }     
  43.     free(buffer);  
  44.     return 0;  
  45. }  
//解碼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. 釋放資源

資源的回收。

  1. void H264_Release(void)  
  2. {  
  3.     avcodec_close(pCodecCtx);  
  4.     av_free(pCodecCtx);  
  5.     av_free(pFrame);  
  6.     av_free(pFrameRGB);  
  7. }