我有下面的代碼使用ffmpeg庫(v3.1.4與Autogen包裝)在我的應用程序中呈現RTSP視頻。代碼一般工作得很好。但是,receptical.Write
方法不是特別有效。在慢速機器上,我的視頻渲染開始落後。最後我的緩衝區滿了,我開始看到視頻損壞。如何更改下面的代碼以在開始落後時跳過幀?如果有多個幀準備好了,我真的只關心顯示最近可用的幀 - 畢竟這是實況視頻。我相信avcodec_send_packet
和avcodec_receive_frame
方法大約是1比1。跳過幀渲染如果落後
while (!token.IsCancellationRequested)
{
if (ffmpeg.av_read_frame(pFormatContext, pPacket) != 0)
{
// end of the stream
ffmpeg.av_packet_unref(pPacket);
ffmpeg.av_frame_unref(pDecodedFrame);
break;
}
if (pPacket->stream_index != pStream->index || (pPacket->flags & ffmpeg.AV_PKT_FLAG_CORRUPT) > 0)
{
// this should never happen; we only subscribe to one stream
// and I believe corrupt packets are automatically discarded
ffmpeg.av_packet_unref(pPacket);
ffmpeg.av_frame_unref(pDecodedFrame);
continue;
}
var sendResult = ffmpeg.avcodec_send_packet(pCodecContext, pPacket);
if (sendResult < 0)
{
// one of the possible results is a "buffer full", but I don't think that should happen as long as we call 1-to-1 receive_frame
ffmpeg.av_packet_unref(pPacket);
ffmpeg.av_frame_unref(pDecodedFrame);
_logger.Warn("Failure in FFmpeg avcodec_send_packet: " + sendResult);
break;
}
while (ffmpeg.avcodec_receive_frame(pCodecContext, pDecodedFrame) == 0)
{
var src = &pDecodedFrame->data0;
var dst = &pConvertedFrame->data0;
var srcStride = pDecodedFrame->linesize;
var dstStride = pConvertedFrame->linesize;
ffmpeg.sws_scale(pConvertContext, src, srcStride, 0, height, dst, dstStride);
sbyte* convertedFrameAddress = pConvertedFrame->data0;
int linesize = dstStride[0];
if (receptical == null)
{
receptical = writableBitampCreationCallback.Invoke(new DetectedImageDimensions {Width = width, Height = height, Format = DetectedPixelFormat.Bgr24, Linesize = linesize});
}
var imageBufferPtr = new IntPtr(convertedFrameAddress);
receptical.Write(width, height, imageBufferPtr, linesize);
ffmpeg.av_frame_unref(pDecodedFrame);
}
ffmpeg.av_packet_unref(pPacket);
}
你覺得我可以用PTS知道我背後不止一個框架?我不熟悉它。 – Brannon
我實際上只是現在就實施它,因爲我不得不對50i幀進行去隔行掃描。我正在同步到系統時鐘,所以當數據包讀取器達到超出2/50秒的數據包時,我不會將它們添加到解碼器。到現在爲止還挺好。所以是的,它可以做到。我只需要這樣做,這樣玩家就可以使用舊的ARM硬件。使用av_q2d()將PTS值轉換爲double。 – WLGfx
我最終不得不爲「av_read_frame」調用使用單獨的線程(因爲在沒有數據可用時它是阻塞調用)。有了這個功能,每當我得到一個新的關鍵幀時,我都會清除我的數據包隊列。現在對我來說這似乎工作得很好。 – Brannon