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不能解碼的問題;