私のアプリケーションでは、RTSPビデオをレンダリングするためにffmpegライブラリ(Autogenラッパーの場合はv3.1.4)を使用する以下のコードがあります。コードは非常によく機能します。しかしながら、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を使用して、私が1つ以上のフレームであることを知ることができると思いますか?私はそれに精通していない。 – Brannon
私は実際にそれを実装しています。なぜなら、50iフレームもインターレース解除する必要があるからです。私はシステムクロックに同期していますので、パケットリーダーが2/50秒のパケットに達したときに、それらをデコーダに追加しません。ここまでは順調ですね。そう、そうすることができます。私はそれを行う必要がありますので、プレーヤーは古いARMハードウェアで作業します。 av_q2d()を使用して、PTS値をdoubleに変換します。 – WLGfx
私は 'av_read_frame'呼び出しのために別のスレッドを使う必要がありました。なぜなら、データが利用できないときはブロック呼び出しであるからです。その場所で、新しいキーフレームを取得するたびにパケットキューをクリアします。それは私のために今かなり良く働いているようです。 – Brannon