FFMPEG.Autogen rtsp video is frequently broken

103 Views Asked by At

I developed an RTSP player with FFMPEG.Autogen in C#.

I want to decode the stream and send it to a bitmap to display a picture box without encoding it.

RTSP video plays fine.

However, my videos often break.

Sometimes the image turns gray and then comes back, or the screen appears as if some part is broken and blurred.

I confirmed that the frame was coming in properly, but there are several hypotheses as to whether it is a problem with the decoded data or because it is run asynchronously, but I do not know the detailed reason.

Please help me.

this is my code

private async void DecodeAllFramesToImages(AVHWDeviceType HWDevice, string rtspUrl)
    {
        await Task.Run(async() =>
        {
            var url = rtspUrl;
            using var vsd = new VideoStreamDecoder(url);
            var info = vsd.GetContextInfo();
            info.ToList().ForEach(x => Console.WriteLine($"{x.Key} = {x.Value}"));

            var sourceSize = vsd.FrameSize;
            var sourcePixelFormat = HWDevice == AVHWDeviceType.AV_HWDEVICE_TYPE_NONE
                ? vsd.PixelFormat
                : GetHWPixelFormat(HWDevice);
            var destinationSize = sourceSize;
            var destinationPixelFormat = AVPixelFormat.AV_PIX_FMT_BGR24;
            Debug.WriteLine(url + " " + sourceSize);

            using var vfc = new VideoFrameConverter(sourceSize, sourcePixelFormat, destinationSize, destinationPixelFormat);

            while (vsd.TryDecodeNextFrame(out var frame))
            {
                if (stopRecord)
                    break;

                var convertedFrame = vfc.Convert(frame);
                Bitmap image = null;
                // Create image without using unsafe block
                unsafe
                {
                    image = new Bitmap(convertedFrame.width, convertedFrame.height, convertedFrame.linesize[0], PixelFormat.Format24bppRgb, (IntPtr)convertedFrame.data[0]);
                }
                await Task.Run(() => UpdatePictureBox(image));
            }
        });
    }

public bool TryDecodeNextFrame(out AVFrame frame)
    {
        ffmpeg.av_frame_unref(_pFrame);
        ffmpeg.av_frame_unref(_receivedFrame);
        int error;

        do
        {
            try
            {
                do
                {
                    ffmpeg.av_packet_unref(_pPacket);
                    error = ffmpeg.av_read_frame(_pFormatContext, _pPacket);

                    if (error == ffmpeg.AVERROR_EOF)
                    {
                        frame = *_pFrame;
                        return false;
                    }

                    error.ThrowExceptionIfError();
                } while (_pPacket->stream_index != _streamIndex);

                ffmpeg.avcodec_send_packet(_pCodecContext, _pPacket).ThrowExceptionIfError();
            }
            catch(Exception ex)
            {
                Debug.WriteLine("UC_MPP.VideoStreamingDecoder.TryDecodeNextFrame : " + ex.Message);
            }
            finally
            {
                ffmpeg.av_packet_unref(_pPacket);
            }

            error = ffmpeg.avcodec_receive_frame(_pCodecContext, _pFrame);
        } while (error == ffmpeg.AVERROR(ffmpeg.EAGAIN));

        error.ThrowExceptionIfError();

        if (_pCodecContext->hw_device_ctx != null)
        {
            ffmpeg.av_hwframe_transfer_data(_receivedFrame, _pFrame, 0).ThrowExceptionIfError();
            frame = *_receivedFrame;
        }
        else
            frame = *_pFrame;

        return true;
    }

public AVFrame Convert(AVFrame sourceFrame)
    {
        ffmpeg.sws_scale(_pConvertContext,
            sourceFrame.data,
            sourceFrame.linesize,
            0,
            sourceFrame.height,
            _dstData,
            _dstLinesize);

        var data = new byte_ptr8();
        data.UpdateFrom(_dstData);
        var linesize = new int8();
        linesize.UpdateFrom(_dstLinesize);

        return new AVFrame
        {
            data = data,
            linesize = linesize,
            width = _destinationSize.Width,
            height = _destinationSize.Height
        };
    }

Thank you for all of your comment.

0

There are 0 best solutions below