1. 程式人生 > >ffmpeg 解碼出現問題,v1.2.1版本,v2.1版本有問題,v0.6.0版本沒有問題

ffmpeg 解碼出現問題,v1.2.1版本,v2.1版本有問題,v0.6.0版本沒有問題

1)當Live555收到的資料中連續來兩個I幀,然後P幀,ffmpeg解碼有問題;

解決辦法:

      當presntationTime不同時候,將以前存的buffer(已經是完整一幀)傳給avcodec_decode_video2解碼; 根據時間戳組幀將sps pps I 幀 I幀的組成一幀,交個ffmpeg解碼,搞定;

2) 通過live555將阿波羅的相機的h264碼流錄製成avi,然後通過ffmpeg轉成.h264,在用live555的testDemandRtspServer例子做伺服器,然後通過testRtspClient做客戶端進行接收,實時解碼,發現前面一個GOP的資料解碼不出來;前面一個GOP也是有sps pps I幀,然後若干P幀的,但是過了一個GOP後,解碼就正常了。詫異!

avcodec_decode_video2返回值=-1;got_picture=0;

錯誤如下:

第一個Gop的第一個I幀 的sps,pps,I幀 的包是分別丟給解碼器的,ffmpeg提示錯誤是no frame!

後面接著的一個P幀,就解碼不出來,提示錯誤Missing reference picture. default is 0

第2個P幀開始的P幀提示錯誤:non-existing PPS 0 referenced.

除錯記錄:

1)根據時間戳不同組包,交給ffmpeg,也是前面一個Gop解碼不出來;

2)後面嘗試第一次從SDP從獲取sps和pps資訊,即第一幀資料是sps pps sps pps I幀,然後是若干個P幀,接著sps pps I幀,這樣也是第一個GOP不能解碼;

3)將第一幀的I幀反覆交給ffmpeg,是可以解碼的;

解決方案:

1)原因ffmpeg v1.2.1 版本,換成老的ffmpeg V0.6.0解決;

為什麼會有問題,還需要分析ffmpeg v1.2.1版本的原始碼,是不是它需要緩衝多少幀,造成前面的一個GOP的影象解碼不出來。

繼續定位發現:v1.2.1 版本的第一個I幀解碼 avcodec_decode_video2返回值為一幀資料的size,但是

len = avcodec_decode_video2(DecodecContext, m_pFrame, &got_picture,&avpkt);

gop_picture的值=0;

環境搭建:

1)  live555 做伺服器;客戶端使用live555接收資料流;然後將接收到的資料幀插入到一個佇列;另外一個顯示執行緒從佇列中取一幀資料進行解碼,顯示;

2)  從2個佇列做緩衝區,首先是一個空的佇列,在上面分配記憶體,形成一個連結串列;收到一幀資料後,從連結串列的頭取一個節點,將一幀資料拷貝到該個節點上,然後插入到另外一個H264資料幀佇列,一定要記得到H264資料幀佇列的尾部;

3)  顯示執行緒從H264佇列的頭取一個節點(一定要從頭開始取節點);然後解碼顯示;

出現過的問題:

1)  插入H264佇列時,插入到佇列的頭,取H264幀的時候也從頭開始取,這樣造成後來的資料顯取了,解碼出錯;

現象:

Live555 sink 的afterGettingFrame函式中進行資料組幀,入佇列操作,由於live555已經將rtp包頭丟掉了,得到的一幀的資料,有可能有4種包,sps pps I 幀,p幀;

組幀策略:

按時間組幀,首先將時間戳相同的資料包組成一幀,然後插入到佇列;

直接在資料到幀前加00 00 00 01 頭後,插入到佇列;

結論:

兩種方法,ffmpeg都可以解碼;使用的是ffmpeg 1.2.1 的版本;但是前面有一個GOP不能解碼,原因不詳;換成v0.6.0版本的ffmpeg庫進行測試;解碼正常!

有誰知道是什麼原因的,麻煩告訴我下,謝謝!

今天又下載了一個最新的版本V2.1進行測試,還是發現前面一個GOP的影象解碼失敗,難道要用回老的版本v0.6.0

問題搞定:

      是初始化解碼器的解析度和實際影象的解析度不一致的問題;本來解碼器是講H264資料解碼成Yuv資料的,但是我將yuv資料轉換到RGB了,給RGB分配了記憶體,在解碼器初始化函式裡面:


#ifdef OUTPUT_RGB

 m_pFrameRGB = avcodec_alloc_frame();
 if(m_pFrameRGB == NULL)
 {
  return false;   
 }

 int numBytes=avpicture_get_size(PIX_FMT_RGB24, DecodecContext->width, DecodecContext->height);
 m_Rgbbuffer=new uint8_t[numBytes];   

 // Assign appropriate parts of buffer to image planes in pFrameRGB
 avpicture_fill((AVPicture *)m_pFrameRGB, m_Rgbbuffer, PIX_FMT_RGB24, DecodecContext->width, DecodecContext->height);

 img_convert_ctx = sws_getContext(DecodecContext->width, DecodecContext->height, DecodecContext->pix_fmt,
  DecodecContext->width, DecodecContext->height, PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);

 if(img_convert_ctx == NULL)
 {
  fprintf(stderr, "Cannot initialize the conversion context!\n");
  return false;
 }

 iDecodeWidth=DecodecContext->width;
 iDecodeHeight=DecodecContext->height;

#endif

實際上,如果不轉RGB是跟解析度沒有關係的,轉RGB後分配的記憶體和解析度有關係,所以在解碼後,判斷解析度和我設定的解析度不一致時,有呼叫了反解碼器函式,釋放ffmpeg的資源,然後在重新呼叫解碼器初始化函式,這樣就出現了前面一個GOP不能解碼的問題;