Recherche avancée

Médias (91)

Autres articles (64)

  • Les autorisations surchargées par les plugins

    27 avril 2010, par

    Mediaspip core
    autoriser_auteur_modifier() afin que les visiteurs soient capables de modifier leurs informations sur la page d’auteurs

  • MediaSPIP Core : La Configuration

    9 novembre 2010, par

    MediaSPIP Core fournit par défaut trois pages différentes de configuration (ces pages utilisent le plugin de configuration CFG pour fonctionner) : une page spécifique à la configuration générale du squelettes ; une page spécifique à la configuration de la page d’accueil du site ; une page spécifique à la configuration des secteurs ;
    Il fournit également une page supplémentaire qui n’apparait que lorsque certains plugins sont activés permettant de contrôler l’affichage et les fonctionnalités spécifiques (...)

  • Supporting all media types

    13 avril 2011, par

    Unlike most software and media-sharing platforms, MediaSPIP aims to manage as many different media types as possible. The following are just a few examples from an ever-expanding list of supported formats : images : png, gif, jpg, bmp and more audio : MP3, Ogg, Wav and more video : AVI, MP4, OGV, mpg, mov, wmv and more text, code and other data : OpenOffice, Microsoft Office (Word, PowerPoint, Excel), web (html, CSS), LaTeX, Google Earth and (...)

Sur d’autres sites (12795)

  • How can I get decoded frames, which I sent into GPU, can i get them from GPU in rgb

    21 mai 2024, par Владислав Сапожник

    I use ffmpeg.av_hwframe_transfer_data to sent decoded frames into GPU, but i can not get them again in another good format. I try to change my shaders, use av_hwframe_transfer_get_formats but it is not working !dfghkdsfiuhsgiherghoeirughoighweroigjoiwejgoiwrjgjeoijgoiewgoheroighoieqfgoihqeoigheiogieiqrhgihergh2eouirghou2rerhg
My code :

    


    {&#xA;    private static bool _readingComplete = false;&#xA;    private static bool _decodingComplete = false;&#xA;    private static readonly object _lock = new object();&#xA;    private static Queue<avpacket> packets = new Queue<avpacket>();&#xA;    private static readonly object _fileLock = new object();&#xA;    public static MyWindow myWindow;&#xA;    public static SKBitmap myBitmap;&#xA;&#xA;    public static async unsafe Task Main(string[] args)&#xA;    {&#xA;        FFmpegBinariesHelper.RegisterFFmpegBinaries();&#xA;        DynamicallyLoadedBindings.Initialize();&#xA;        Console.WriteLine($"FFmpeg version info: {ffmpeg.av_version_info()}");&#xA;&#xA;        Directory.Delete("frames", true);&#xA;        Directory.CreateDirectory("frames");&#xA;&#xA;        var url = "rtsp://admin:123456@192.168.1.12:554/stream0?username=admin&amp;password=E10ADC3949BA59ABBE56E057F20";&#xA;&#xA;        AVDictionary* opts = null;&#xA;        ffmpeg.av_dict_set(&amp;opts, "-rtsp_transport", "tcp", 0);&#xA;&#xA;        var vsr = new VideoStreamReader(url, opts);&#xA;        var vsd = new VideoStreamDecoder(*vsr.GetCodecParameters(), AVHWDeviceType.AV_HWDEVICE_TYPE_D3D11VA);&#xA;&#xA;        Task readerTask = Task.Factory.StartNew(() => ReadPackets(vsr), TaskCreationOptions.LongRunning);&#xA;        Task decoderTask = Task.Factory.StartNew(() => DecodeFrames(vsd), TaskCreationOptions.LongRunning);&#xA;&#xA;        var nativeWindowSettings = new NativeWindowSettings()&#xA;        {&#xA;            ClientSize = new Vector2i(800, 600),&#xA;            Title = "My first OpenTK program!"&#xA;        };&#xA;&#xA;        using (var myWindow = new MyWindow(GameWindowSettings.Default, nativeWindowSettings))&#xA;        {&#xA;            myWindow.Run();&#xA;        }&#xA;    }&#xA;&#xA;    private static unsafe void ReadPackets(VideoStreamReader vsr)&#xA;    {&#xA;        while (!_readingComplete)&#xA;        {&#xA;            vsr.TryReadNextPacket(out var packet);&#xA;            lock (_lock)&#xA;            {&#xA;                packets.Enqueue(packet);&#xA;            }&#xA;        }&#xA;&#xA;        _readingComplete = true;&#xA;    }&#xA;&#xA;    private static unsafe void DecodeFrames(VideoStreamDecoder vsd)&#xA;    {&#xA;&#xA;        Console.WriteLine($"codec name: {vsd.CodecName}");&#xA;&#xA;        //var sourceSize = vsd.FrameSize;&#xA;        //var sourcePixelFormat = vsd.PixelFormat;&#xA;        //var destinationSize = sourceSize;&#xA;        //var destinationPixelFormat = AVPixelFormat.AV_PIX_FMT_RGBA;&#xA;        //using var vfc = new VideoFrameConverter(sourceSize, sourcePixelFormat, destinationSize, destinationPixelFormat);&#xA;&#xA;        var frameNumber = 0;&#xA;&#xA;        while (true)&#xA;        {&#xA;            AVPacket packet;&#xA;            lock (_lock)&#xA;            {&#xA;                if (packets.Count == 0)&#xA;                {&#xA;                    if (_readingComplete)&#xA;                    {&#xA;                        break;&#xA;                    }&#xA;                    else&#xA;                    {&#xA;                        continue;&#xA;                    }&#xA;                }&#xA;                packet = packets.Dequeue();&#xA;            }&#xA;&#xA;            vsd.TryDecodeNextFrame(out var frame, packet);&#xA;            //var convertedFrame = vfc.Convert(frame);&#xA;&#xA;            //var bitmap = new SKBitmap(convertedFrame.width, convertedFrame.height, SKColorType.Bgra8888, SKAlphaType.Opaque);&#xA;            //bitmap.InstallPixels(new SKImageInfo(convertedFrame.width, convertedFrame.height, SKColorType.Bgra8888, SKAlphaType.Opaque), (IntPtr)convertedFrame.data[0]);&#xA;            //myBitmap = bitmap;&#xA;            var bitmap = new SKBitmap(frame.width, frame.height, SKColorType.Bgra8888, SKAlphaType.Opaque);&#xA;            bitmap.InstallPixels(new SKImageInfo(frame.width, frame.height, SKColorType.Bgra8888, SKAlphaType.Opaque), (IntPtr)frame.data[0]);&#xA;            myBitmap = bitmap;&#xA;            &#xA;            Console.WriteLine($"frame: {frameNumber}");&#xA;            frameNumber&#x2B;&#x2B;;&#xA;        }&#xA;&#xA;        _decodingComplete = true;&#xA;    }&#xA;&#xA;    //private static unsafe void WriteFrame(AVFrame convertedFrame, int frameNumber)&#xA;    //{&#xA;    //    var imageInfo = new SKImageInfo(convertedFrame.width, convertedFrame.height, SKColorType.Bgra8888, SKAlphaType.Opaque);&#xA;    //    using var bitmap = new SKBitmap();&#xA;    //    bitmap.InstallPixels(imageInfo, (IntPtr)convertedFrame.data[0]);&#xA;&#xA;    //    string filePath;&#xA;    //    lock (_fileLock)&#xA;    //    {&#xA;    //        filePath = $"frames/frame.{frameNumber:D8}.jpg";&#xA;    //    }&#xA;&#xA;    //    using var stream = File.Create(filePath);&#xA;    //    bitmap.Encode(stream, SKEncodedImageFormat.Jpeg, 90);&#xA;    //}&#xA;}&#xA;using OpenTK.Graphics.OpenGL4;&#xA;using OpenTK.Mathematics;&#xA;using OpenTK.Windowing.Common;&#xA;using OpenTK.Windowing.Desktop;&#xA;using OpenTK.Windowing.GraphicsLibraryFramework;&#xA;using SkiaSharp;&#xA;&#xA;namespace OpenTKTask;&#xA;&#xA;public class MyWindow : GameWindow&#xA;{&#xA;    private Shader shader;&#xA;    private int vertexBufferHandle;&#xA;    private int elementBufferHandle;&#xA;    private int vertexArrayHandle;&#xA;    private int texture;&#xA;&#xA;    //float[] vertices =&#xA;    //{&#xA;    //    1.0f, 1.0f, 0.0f, 1.0f, 0.0f,&#xA;    //    1.0f, -1.0f, 0.0f, 1.0f, 1.0f,&#xA;    //    -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,&#xA;    //    -1.0f, 1.0f, 0.0f, 0.0f, 1.0f&#xA;    //};&#xA;&#xA;    float[] vertices =&#xA;{&#xA;    //Position         | Texture coordinates&#xA;     1.0f,  1.0f, 0.0f, 1.0f, 0.0f, // top right&#xA;     1.0f, -1.0f, 0.0f, 1.0f, 1.0f, // bottom right&#xA;    -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, // bottom left&#xA;    -1.0f,  1.0f, 0.0f, 0.0f, 0.0f  // top left&#xA;};&#xA;&#xA;    uint[] indices =&#xA;{&#xA;        0, 1, 3,&#xA;        1, 2, 3&#xA;    };&#xA;&#xA;    float[] texCoords =&#xA;    {&#xA;        0.0f, 0.0f,&#xA;        1.0f, 0.0f,&#xA;        0.5f, 1.0f,&#xA;    };&#xA;&#xA;    public MyWindow(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings) : base(gameWindowSettings, nativeWindowSettings)&#xA;    {&#xA;        this.CenterWindow(new Vector2i(1280, 760));&#xA;    }&#xA;&#xA;    protected override void OnResize(ResizeEventArgs e)&#xA;    {&#xA;        GL.Viewport(0, 0, e.Width, e.Height);&#xA;        base.OnResize(e);&#xA;    }&#xA;&#xA;    protected override void OnLoad()&#xA;    {&#xA;        base.OnLoad();&#xA;&#xA;        shader = new Shader("C:\\Users\\1\\Desktop\\7h3_C0d3r\\OpenTKTask\\vertexShader.vert", "C:\\Users\\1\\Desktop\\7h3_C0d3r\\OpenTKTask\\fragShader.frag");&#xA;        shader.Use();&#xA;&#xA;        vertexArrayHandle = GL.GenVertexArray();&#xA;        GL.BindVertexArray(vertexArrayHandle);&#xA;&#xA;        vertexBufferHandle = GL.GenBuffer();&#xA;        GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferHandle);&#xA;        GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw);&#xA;&#xA;        elementBufferHandle = GL.GenBuffer();&#xA;        GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferHandle);&#xA;        GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(uint), indices, BufferUsageHint.StaticDraw);&#xA;&#xA;        var positionLocation = shader.GetAttribLocation("aPosition");&#xA;        GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float, false, 5 * sizeof(float), 0);&#xA;        GL.EnableVertexAttribArray(positionLocation);&#xA;&#xA;        var texCoordLocation = shader.GetAttribLocation("aTexCoord");&#xA;        GL.VertexAttribPointer(texCoordLocation, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), 3 * sizeof(float));&#xA;        GL.EnableVertexAttribArray(texCoordLocation);&#xA;&#xA;        texture = GL.GenTexture();&#xA;        GL.BindTexture(TextureTarget.Texture2D, texture);&#xA;&#xA;        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);&#xA;        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);&#xA;        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);&#xA;        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);&#xA;&#xA;        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, 800, 600, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero);&#xA;        GL.BindTexture(TextureTarget.Texture2D, 0);&#xA;    }&#xA;&#xA;    protected override void OnUnload()&#xA;    {&#xA;        base.OnUnload();&#xA;        GL.DeleteBuffer(vertexBufferHandle);&#xA;        GL.DeleteVertexArray(vertexArrayHandle);&#xA;        GL.DeleteProgram(shader.Handle);&#xA;        GL.DeleteTexture(texture);&#xA;    }&#xA;&#xA;    protected override void OnUpdateFrame(FrameEventArgs args)&#xA;    {&#xA;        base.OnUpdateFrame(args);&#xA;    }&#xA;&#xA;    protected override void OnRenderFrame(FrameEventArgs args)&#xA;    {&#xA;        base.OnRenderFrame(args);&#xA;&#xA;        UpdateTexture(Program.myBitmap);&#xA;&#xA;        GL.Clear(ClearBufferMask.ColorBufferBit);&#xA;&#xA;        GL.BindTexture(TextureTarget.Texture2D, texture);&#xA;&#xA;        shader.Use();&#xA;&#xA;        GL.BindVertexArray(vertexArrayHandle);&#xA;&#xA;        GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0);&#xA;&#xA;        SwapBuffers();&#xA;    }&#xA;&#xA;    public void UpdateTexture(SKBitmap bitmap)&#xA;    {&#xA;        GL.BindTexture(TextureTarget.Texture2D, texture);&#xA;&#xA;        if (bitmap != null)&#xA;        {&#xA;            //byte[] pixels = bitmap.Bytes;&#xA;            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bitmap.Width, bitmap.Height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, 0);&#xA;        }&#xA;    }&#xA;&#xA;    public SKBitmap LoadBitmap(string path)&#xA;    {&#xA;        using (var stream = File.OpenRead(path))&#xA;        {&#xA;            return SKBitmap.Decode(stream);&#xA;        }&#xA;    }&#xA;}&#xA;using FFmpeg.AutoGen;&#xA;using System.Drawing;&#xA;&#xA;namespace OpenTKTask;&#xA;&#xA;public sealed unsafe class VideoStreamDecoder : IDisposable&#xA;{&#xA;    private readonly AVCodecContext* _pCodecContext;&#xA;    private readonly AVPacket* _pPacket;&#xA;    private readonly AVFrame* _pFrame;&#xA;    private readonly AVFrame* _receivedFrame;&#xA;    private AVFrame* _pSwFrame;&#xA;    private AVBufferRef* _pHWDeviceCtx;&#xA;&#xA;    public VideoStreamDecoder(AVCodecParameters parameter, AVHWDeviceType HWDeviceType = AVHWDeviceType.AV_HWDEVICE_TYPE_D3D12VA)&#xA;    {&#xA;        _receivedFrame = ffmpeg.av_frame_alloc();&#xA;&#xA;        AVCodec* codec = ffmpeg.avcodec_find_decoder(parameter.codec_id);&#xA;        if (codec == null)&#xA;            throw new InvalidOperationException("Codec not found.");&#xA;        _pCodecContext = ffmpeg.avcodec_alloc_context3(codec);&#xA;&#xA;        ffmpeg.av_hwdevice_ctx_create(&amp;_pCodecContext->hw_device_ctx, HWDeviceType, null, null, 0).ThrowExceptionIfError();&#xA;&#xA;        ffmpeg.avcodec_parameters_to_context(_pCodecContext, &amp;parameter)&#xA;            .ThrowExceptionIfError();&#xA;        ffmpeg.avcodec_open2(_pCodecContext, codec, null).ThrowExceptionIfError();&#xA;&#xA;        CodecName = ffmpeg.avcodec_get_name(codec->id);&#xA;        FrameSize = new Size(_pCodecContext->width, _pCodecContext->height);&#xA;        PixelFormat = _pCodecContext->pix_fmt;&#xA;&#xA;        _pFrame = ffmpeg.av_frame_alloc();&#xA;        _pPacket = ffmpeg.av_packet_alloc();&#xA;    }&#xA;&#xA;    public string CodecName { get; }&#xA;    public Size FrameSize { get; }&#xA;    public AVPixelFormat PixelFormat { get; }&#xA;&#xA;    public bool TryDecodeNextFrame(out AVFrame frame, AVPacket packet)&#xA;    {&#xA;        ffmpeg.av_frame_unref(_pFrame);&#xA;        ffmpeg.av_frame_unref(_receivedFrame);&#xA;        int error;&#xA;&#xA;        do&#xA;        {&#xA;            ffmpeg.avcodec_send_packet(_pCodecContext, &amp;packet).ThrowExceptionIfError();&#xA;            error = ffmpeg.avcodec_receive_frame(_pCodecContext, _pFrame);&#xA;        } while (error == ffmpeg.AVERROR(ffmpeg.EAGAIN));&#xA;&#xA;        error.ThrowExceptionIfError();&#xA;&#xA;        if (_pCodecContext->hw_device_ctx != null)&#xA;        {&#xA;            ffmpeg.av_hwframe_transfer_data(_receivedFrame, _pFrame, 0).ThrowExceptionIfError();&#xA;            Console.WriteLine((AVPixelFormat)171);&#xA;            frame = *_receivedFrame; // AV_PIX_FMT_NV11&#xA;            //Console.WriteLine((AVPixelFormat)frame.format);&#xA;        }&#xA;        else&#xA;            frame = *_pFrame; // AV_PIX_FMT_NV11&#xA;        //Console.WriteLine((AVPixelFormat)frame.format);&#xA;        return true;&#xA;    }&#xA;&#xA;    public void Dispose()&#xA;    {&#xA;        var pFrame = _pFrame;&#xA;        ffmpeg.av_frame_free(&amp;pFrame);&#xA;&#xA;        var pCodecContext = _pCodecContext;&#xA;        ffmpeg.avcodec_free_context(&amp;pCodecContext);&#xA;&#xA;        if (_pHWDeviceCtx != null)&#xA;        {&#xA;            var pHWDeviceCtx = _pHWDeviceCtx;&#xA;            ffmpeg.av_buffer_unref(&amp;pHWDeviceCtx);&#xA;        }&#xA;&#xA;        if (_pSwFrame != null)&#xA;        {&#xA;            var pSwFrame = _pSwFrame;&#xA;            ffmpeg.av_frame_free(&amp;pSwFrame);&#xA;        }&#xA;    }&#xA;}````&#xA;</avpacket></avpacket>

    &#xA;

  • Render YUV frame using OpenTK [closed]

    20 mai 2024, par dima2012 terminator

    my window&#xA;Im trying to render YUV AVFrame, that i get from camera using OpenTK, im creating a rectangle and trying to apply a texture to it, but it doesnt work.

    &#xA;

    Here is my window class

    &#xA;

    using OpenTK.Graphics.Egl;&#xA;using OpenTK.Graphics.OpenGL4;&#xA;using OpenTK.Windowing.Common;&#xA;using OpenTK.Windowing.Desktop;&#xA;using OpenTK.Windowing.GraphicsLibraryFramework;&#xA;using System;&#xA;using System.Collections.Generic;&#xA;using System.Diagnostics;&#xA;using System.Linq;&#xA;using System.Text;&#xA;using System.Threading;&#xA;using System.Threading.Tasks;&#xA;&#xA;namespace myFFmpeg&#xA;{&#xA;    public class CameraWindow : GameWindow&#xA;    {&#xA;        private int vertexBufferHandle;&#xA;        private int elementBufferHandle;&#xA;        private int vertexArrayHandle;&#xA;        private int frameNumber = 0;&#xA;        private int yTex, uTex, vTex;&#xA;&#xA;        Shader shader;&#xA;        Texture texture;&#xA;&#xA;        float[] vertices =&#xA;        {&#xA;            //Position         | Texture coordinates&#xA;             0.5f,  0.5f, 0.0f, 1.0f, 0.0f, // top right&#xA;             0.5f, -0.5f, 0.0f, 1.0f, 1.0f, // bottom right&#xA;            -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // bottom left&#xA;            -0.5f,  0.5f, 0.0f, 0.0f, 0.0f  // top left&#xA;        };&#xA;&#xA;&#xA;        private uint[] indices = &#xA;        {&#xA;            0, 1, 3,   // first triangle&#xA;            1, 2, 3    // second triangle&#xA;        };&#xA;&#xA;        public CameraWindow(string title) : base(GameWindowSettings.Default, new NativeWindowSettings() { ClientSize = (1280, 720), Title = title }) { UpdateFrequency = 25; }&#xA;&#xA;        protected override void OnUpdateFrame(FrameEventArgs e)&#xA;        {&#xA;            base.OnUpdateFrame(e);&#xA;        }&#xA;&#xA;        protected override void OnLoad()&#xA;        {&#xA;            GL.ClearColor(0.5f, 0.3f, 0.3f, 1.0f);&#xA;&#xA;            shader = new Shader(@"..\..\shader.vert", @"..\..\shader.frag");&#xA;            texture = new Texture();&#xA;&#xA;            elementBufferHandle = GL.GenBuffer();&#xA;            GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferHandle);&#xA;            GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(uint), indices, BufferUsageHint.StaticDraw);&#xA;&#xA;            vertexBufferHandle = GL.GenBuffer();&#xA;            GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferHandle);&#xA;            GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw);&#xA;&#xA;            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);&#xA;&#xA;            vertexArrayHandle = GL.GenVertexArray();&#xA;            GL.BindVertexArray(vertexArrayHandle);&#xA;&#xA;            GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferHandle);&#xA;            GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 5 * sizeof(float), 0);&#xA;            GL.EnableVertexAttribArray(0);&#xA;&#xA;            int vertexShader = GL.CreateShader(ShaderType.VertexShader);&#xA;            GL.ShaderSource(vertexShader, @"..\..\shader.vert");&#xA;            GL.CompileShader(vertexShader);&#xA;&#xA;            int fragmentShader = GL.CreateShader(ShaderType.FragmentShader);&#xA;            GL.ShaderSource(fragmentShader, @"..\..\shader.frag");&#xA;            GL.CompileShader(fragmentShader);&#xA;&#xA;            int shaderProgram = GL.CreateProgram();&#xA;            GL.AttachShader(shaderProgram, vertexShader);&#xA;            GL.AttachShader(shaderProgram, fragmentShader);&#xA;            GL.LinkProgram(shaderProgram);&#xA;&#xA;&#xA;            int vertexPosLocation = GL.GetAttribLocation(shaderProgram, "vertexPos");&#xA;            GL.EnableVertexAttribArray(vertexPosLocation);&#xA;            GL.VertexAttribPointer(vertexPosLocation, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 0);&#xA;&#xA;            int texCoordLocation = GL.GetAttribLocation(shaderProgram, "texCoord");&#xA;            GL.EnableVertexAttribArray(texCoordLocation);&#xA;            GL.VertexAttribPointer(texCoordLocation, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2 * sizeof(float));&#xA;&#xA;            GL.UseProgram(shaderProgram);&#xA;&#xA;            GL.ActiveTexture(TextureUnit.Texture0);&#xA;            GL.BindTexture(TextureTarget.Texture2D, yTex);&#xA;            GL.Uniform1(GL.GetUniformLocation(shaderProgram, "yTex"), 0);&#xA;&#xA;            GL.ActiveTexture(TextureUnit.Texture1);&#xA;            GL.BindTexture(TextureTarget.Texture2D, uTex);&#xA;            GL.Uniform1(GL.GetUniformLocation(shaderProgram, "uTex"), 1);&#xA;&#xA;            GL.ActiveTexture(TextureUnit.Texture2);&#xA;            GL.BindTexture(TextureTarget.Texture2D, vTex);&#xA;            GL.Uniform1(GL.GetUniformLocation(shaderProgram, "vTex"), 2);&#xA;&#xA;            GL.BindVertexArray(0);&#xA;            //code&#xA;&#xA;            base.OnLoad();&#xA;        }&#xA;&#xA;        protected override void OnUnload()&#xA;        {&#xA;            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);&#xA;            GL.DeleteBuffer(vertexBufferHandle);&#xA;            GL.UseProgram(0);&#xA;            shader.Dispose();&#xA;&#xA;            //code&#xA;&#xA;            base.OnUnload();&#xA;        }&#xA;&#xA;        protected override void OnRenderFrame(FrameEventArgs e)&#xA;        {&#xA;&#xA;            GL.Clear(ClearBufferMask.ColorBufferBit);&#xA;&#xA;            shader.Use();&#xA;            texture.Use(frameNumber&#x2B;&#x2B;);&#xA;&#xA;            GL.BindVertexArray(vertexArrayHandle);&#xA;&#xA;            GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, indices);&#xA;&#xA;            Context.SwapBuffers();&#xA;&#xA;            base.OnRenderFrame(e);&#xA;        }&#xA;&#xA;        protected override void OnFramebufferResize(FramebufferResizeEventArgs e)&#xA;        {&#xA;            base.OnFramebufferResize(e);&#xA;&#xA;            GL.Viewport(0, 0, e.Width, e.Height);&#xA;        }&#xA;    }&#xA;}&#xA;

    &#xA;

    And my texture class :

    &#xA;

    using System;&#xA;using OpenTK;&#xA;using OpenTK.Graphics.OpenGL4;&#xA;using SkiaSharp;&#xA;using FFmpeg;&#xA;using SkiaSharp.Internals;&#xA;using StbImageSharp;&#xA;using FFmpeg.AutoGen;&#xA;using System.Threading;&#xA;&#xA;namespace myFFmpeg&#xA;{&#xA;    public class Texture&#xA;    {&#xA;        int Handle, yTex, uTex, vTex;&#xA;&#xA;        Program program = new Program();&#xA;&#xA;        public Texture()&#xA;        {&#xA;            Handle = GL.GenTexture();&#xA;        }&#xA;&#xA;&#xA;        public unsafe void Use(int frameNumber)&#xA;        {&#xA;            GL.BindTexture(TextureTarget.Texture2D, Handle);&#xA;&#xA;            // Generate textures only once (outside the loop)&#xA;            if (yTex == 0)&#xA;            {&#xA;                GL.GenTextures(1, out yTex);&#xA;            }&#xA;            if (uTex == 0)&#xA;            {&#xA;                GL.GenTextures(1, out uTex);&#xA;            }&#xA;            if (vTex == 0)&#xA;            {&#xA;                GL.GenTextures(1, out vTex);&#xA;            }&#xA;&#xA;            // Bind textures to specific units before rendering each frame&#xA;            GL.ActiveTexture(TextureUnit.Texture0);&#xA;            GL.BindTexture(TextureTarget.Texture2D, yTex);&#xA;            GL.ActiveTexture(TextureUnit.Texture1);&#xA;            GL.BindTexture(TextureTarget.Texture2D, uTex);&#xA;            GL.ActiveTexture(TextureUnit.Texture2);&#xA;&#xA;            // Update textures with new frame data from FFmpeg&#xA;            AVFrame frame = program.getFrame();&#xA;            int width = frame.width;&#xA;            int height = frame.height;&#xA;&#xA;            Console.BackgroundColor = ConsoleColor.White;&#xA;            Console.ForegroundColor = ConsoleColor.Black;&#xA;            Console.WriteLine((AVPixelFormat)frame.format);&#xA;            Console.BackgroundColor = ConsoleColor.Black;&#xA;&#xA;&#xA;            // Assuming YUV data is stored in separate planes (Y, U, V)&#xA;            GL.BindTexture(TextureTarget.Texture2D, yTex);&#xA;            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Luminance, width, height, 0, PixelFormat.Luminance, PixelType.UnsignedByte, (IntPtr)frame.data[0]);&#xA;            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);&#xA;            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);&#xA;&#xA;            GL.BindTexture(TextureTarget.Texture2D, uTex);&#xA;            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Luminance, width / 2, height / 2, 0, PixelFormat.Luminance, PixelType.UnsignedByte, (IntPtr)frame.data[1]);&#xA;            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);&#xA;            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);&#xA;&#xA;            GL.BindTexture(TextureTarget.Texture2D, vTex);&#xA;            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Luminance, width / 2, height / 2, 0, PixelFormat.Luminance, PixelType.UnsignedByte, (IntPtr)frame.data[2]);&#xA;            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);&#xA;            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);&#xA;&#xA;        }&#xA;    }&#xA;}&#xA;&#xA;

    &#xA;

    And my shader class :

    &#xA;

    using OpenTK.Graphics.OpenGL4;&#xA;using System;&#xA;using System.IO;&#xA;&#xA;namespace myFFmpeg&#xA;{&#xA;    public class Shader : IDisposable&#xA;    {&#xA;        public int Handle { get; private set; }&#xA;&#xA;        public Shader(string vertexPath, string fragmentPath)&#xA;        {&#xA;            string vertexShaderSource = File.ReadAllText(vertexPath);&#xA;            string fragmentShaderSource = File.ReadAllText(fragmentPath);&#xA;&#xA;            int vertexShader = GL.CreateShader(ShaderType.VertexShader);&#xA;            GL.ShaderSource(vertexShader, vertexShaderSource);&#xA;            GL.CompileShader(vertexShader);&#xA;            CheckShaderCompilation(vertexShader);&#xA;&#xA;            int fragmentShader = GL.CreateShader(ShaderType.FragmentShader);&#xA;            GL.ShaderSource(fragmentShader, fragmentShaderSource);&#xA;            GL.CompileShader(fragmentShader);&#xA;            CheckShaderCompilation(fragmentShader);&#xA;&#xA;            Handle = GL.CreateProgram();&#xA;            GL.AttachShader(Handle, vertexShader);&#xA;            GL.AttachShader(Handle, fragmentShader);&#xA;            GL.LinkProgram(Handle);&#xA;            CheckProgramLinking(Handle);&#xA;&#xA;            GL.DetachShader(Handle, vertexShader);&#xA;            GL.DetachShader(Handle, fragmentShader);&#xA;            GL.DeleteShader(vertexShader);&#xA;            GL.DeleteShader(fragmentShader);&#xA;        }&#xA;&#xA;        public void Use()&#xA;        {&#xA;            GL.UseProgram(Handle);&#xA;        }&#xA;&#xA;        public int GetAttribLocation(string attribName)&#xA;        {&#xA;            return GL.GetAttribLocation(Handle, attribName);&#xA;        }&#xA;&#xA;        public int GetUniformLocation(string uniformName)&#xA;        {&#xA;            return GL.GetUniformLocation(Handle, uniformName);&#xA;        }&#xA;&#xA;        private void CheckShaderCompilation(int shader)&#xA;        {&#xA;            GL.GetShader(shader, ShaderParameter.CompileStatus, out int success);&#xA;            if (success == 0)&#xA;            {&#xA;                string infoLog = GL.GetShaderInfoLog(shader);&#xA;                throw new InvalidOperationException($"Shader compilation failed: {infoLog}");&#xA;            }&#xA;        }&#xA;&#xA;        private void CheckProgramLinking(int program)&#xA;        {&#xA;            GL.GetProgram(program, GetProgramParameterName.LinkStatus, out int success);&#xA;            if (success == 0)&#xA;            {&#xA;                string infoLog = GL.GetProgramInfoLog(program);&#xA;                throw new InvalidOperationException($"Program linking failed: {infoLog}");&#xA;            }&#xA;        }&#xA;&#xA;        public void Dispose()&#xA;        {&#xA;            GL.DeleteProgram(Handle);&#xA;        }&#xA;    }&#xA;}&#xA;

    &#xA;

    Vert shader

    &#xA;

    #version 330 core&#xA;layout(location = 0) in vec3 vertexPos;&#xA;layout(location = 1) in vec2 texCoord;&#xA;&#xA;out vec2 TexCoord; &#xA;&#xA;void main()&#xA;{&#xA;    gl_Position = vec4(vertexPos,1.0);&#xA;    TexCoord = texCoord;&#xA;}&#xA;

    &#xA;

    Frag shader

    &#xA;

    #version 330 core&#xA;in vec2 TexCoord;&#xA;out vec4 color;&#xA;&#xA;uniform sampler2D yTex;&#xA;uniform sampler2D uTex;&#xA;uniform sampler2D vTex;&#xA;&#xA;void main()&#xA;{&#xA;  float y = texture(yTex, TexCoord).r;&#xA;  float u = texture(uTex, TexCoord).r - 0.5;&#xA;  float v = texture(vTex, TexCoord).r - 0.5;&#xA;&#xA;  // YUV to RGB conversion (BT.709)&#xA;  float r = y &#x2B; 1.5714 * v;&#xA;  float g = y - 0.6486 * u - 0.3918 * v;&#xA;  float b = y &#x2B; 1.8556 * u;&#xA;&#xA;  color = vec4(r, g, b, 1.0);&#xA;}&#xA;

    &#xA;

    I can provide more code, if needed..

    &#xA;

    I tried changing shaders, changing textures, getting frame using ffmpeg.av_hwframe_transfer_data(_receivedFrame, _pFrame, 0);

    &#xA;

  • Display real time frames from several RTSP streams

    13 février 2024, par Mrax

    I have this class, it uses ffmpeg library for rtsp live streaming :

    &#xA;

    #include <iostream>&#xA;#include <string>&#xA;#include <vector>&#xA;#include <mutex>&#xA;&#xA;extern "C"&#xA;{&#xA;#include <libavcodec></libavcodec>avcodec.h>&#xA;#include <libavformat></libavformat>avformat.h>&#xA;#include <libavformat></libavformat>avio.h>&#xA;}&#xA;&#xA;class ryMediaSource&#xA;{&#xA;public:&#xA;    ryMediaSource() {}&#xA;    ryMediaSource(const ryMediaSource&amp; other);&#xA;    ~ryMediaSource();&#xA;&#xA;    bool ryOpenMediaSource(const std::string&amp;);&#xA;&#xA;private:&#xA;    mediaSource pMediaSource;&#xA;    AVFormatContext* pFormatCtx;&#xA;    mutable std::mutex pMutex;&#xA;};&#xA;</mutex></vector></string></iostream>

    &#xA;

    And inside my main file, I have these vector of ryMediaSource and four rstp urls :

    &#xA;

    std::vector<rymediasource> mediaSources;&#xA;std::vector streams =&#xA;{&#xA;    {"rtsp://1&#xA;    {"rtsp://2&#xA;    {"rtsp://3&#xA;    {"rtsp://4&#xA;};&#xA;</rymediasource>

    &#xA;

    Creating a instance for every vector :

    &#xA;

    for (const auto&amp; stream : streams)&#xA;{&#xA;    mediaSources.emplace_back(); // Create a new instance for each stream&#xA;}&#xA;

    &#xA;

    And opening all the streams (I need to have access to all the streams, all the time).

    &#xA;

    for (size_t s = 0; s &lt; streams.size(); s&#x2B;&#x2B;)&#xA;{&#xA;     mediaSources[s].ryOpenMediaSource(streams[s]);&#xA;}&#xA;

    &#xA;

    After all the streams are loaded, I start to display the videos all of the streams : av_read_frame(pFormatCtx, pPacket).&#xA;But I am having a gap from what is been displayed to what is really capturing from the source (IP Cameras).&#xA;From ryOpenMediaSource(streams[0]) is about 11 seconds, ryOpenMediaSource(streams[1]) about 7 seconds, ryOpenMediaSource(streams[2]) is about 4 seconds and ryOpenMediaSource(streams[3]) is real time.&#xA;I realized that the issue is on my ryOpenMediaSource code :

    &#xA;

    bool ryMediaSource::ryOpenMediaSource(const std::string&amp; url)&#xA;{&#xA;    int rc = -1;&#xA;&#xA;    pFormatCtx = avformat_alloc_context();&#xA;    if (!pFormatCtx)&#xA;        throw std::runtime_error("Failed to allocate AVFormatContext.");&#xA;    rc = avformat_open_input(&amp;pFormatCtx, url.c_str(), NULL, NULL);&#xA;    if (rc &lt; 0)&#xA;    {&#xA;        return false;&#xA;    }&#xA;}&#xA;

    &#xA;

    My question is, why this is happening ? Why can't all streams have the same (time stamp ?) , as the last inserted in my vector of ryMediaSource ?

    &#xA;

    Should I overwrite some variable of pFormatCtx to "force" the all vector to have the (time stamp ?) as the last one ? If so, can you give me some guidance ?

    &#xA;

    Tried setting some different values on pFormatCtx after loaded with avformat_open_input(&pFormatCtx, url.c_str(), NULL, &pDicts) ; but no luck at all.

    &#xA;

    I am expecting that all streams started at the same time, even if pre loading them, for later on, transform these frames into a cv::Mat for rendering.

    &#xA;

    MRE :

    &#xA;

    Header :&#xA;&#xA;#pragma once&#xA;&#xA;#include <iostream>&#xA;#include <string>&#xA;#include <vector>&#xA;#include <chrono>&#xA;#include <thread>&#xA;#include <mutex>&#xA;&#xA;&#xA;extern "C"&#xA;{&#xA;#include <libavcodec></libavcodec>avcodec.h>&#xA;#include <libavformat></libavformat>avformat.h>&#xA;#include <libavutil></libavutil>pixdesc.h>&#xA;#include <libavutil></libavutil>hwcontext.h>&#xA;#include <libavutil></libavutil>opt.h>&#xA;#include <libavutil></libavutil>avassert.h>&#xA;#include <libavutil></libavutil>imgutils.h>&#xA;#include <libswscale></libswscale>swscale.h>&#xA;#include <libavdevice></libavdevice>avdevice.h>&#xA;#include <libavformat></libavformat>avio.h>&#xA;#include <libavutil></libavutil>time.h>&#xA;}&#xA;&#xA;class ryMediaSource&#xA;{&#xA;public:&#xA;    ryMediaSource() {}&#xA;    ryMediaSource(const ryMediaSource&amp; other);&#xA;    ~ryMediaSource();&#xA;&#xA;    struct mediaSourceParams&#xA;    {&#xA;        int sx;&#xA;        int sy;&#xA;        int lsize;&#xA;        double fps;&#xA;        unsigned char* frame;&#xA;    };&#xA;&#xA;    bool ryOpenMediaSource(const std::string&amp;);&#xA;    mediaSourceParams ryGetMediaSourceFrame();&#xA;    void ryCloseMediaSource();&#xA;&#xA;private:&#xA;    mediaSource pMediaSource;&#xA;    AVFormatContext* pFormatCtx;&#xA;    AVCodecContext* pCodecCtx;&#xA;    AVFrame* pFrame;&#xA;    SwsContext* pSwsCtx;&#xA;    AVPacket* pPacket;&#xA;    int pVideoStream;&#xA;    uint8_t* pBuffer;&#xA;    AVFrame* pPict;&#xA;    double pFPS;&#xA;    mutable std::mutex pMutex;&#xA;};&#xA;&#xA;C&#x2B;&#x2B; source code :&#xA;&#xA;#include "ryMediaSource.hpp"&#xA;&#xA;ryMediaSource::ryMediaSource(const ryMediaSource&amp; other)&#xA;:pFormatCtx(nullptr), &#xA;pCodecCtx(nullptr), &#xA;pFrame(nullptr), &#xA;pSwsCtx(nullptr), &#xA;pPacket(nullptr), &#xA;pBuffer(nullptr), &#xA;pPict(nullptr)&#xA;{&#xA;    std::lock_guard lock(other.pMutex);&#xA;    av_log_set_level(0);&#xA;    avformat_network_init();&#xA;}&#xA;&#xA;bool ryMediaSource::ryOpenMediaSource(const std::string&amp; url)&#xA;{&#xA;    int rc = -1;&#xA;&#xA;    try&#xA;    {&#xA;        AVDictionary* pDicts = nullptr;&#xA;&#xA;        pFormatCtx = avformat_alloc_context();&#xA;        if (!pFormatCtx)&#xA;            throw std::runtime_error("Failed to allocate AVFormatContext.");&#xA;        rc = av_dict_set(&amp;pDicts, "rtsp_transport", "tcp", 0);&#xA;        if (rc &lt; 0)&#xA;            throw std::runtime_error("av_dict_set failed.");&#xA;                rc = avformat_open_input(&amp;pFormatCtx, url.c_str(), NULL, &amp;pDicts);&#xA;        if (rc &lt; 0)&#xA;        {&#xA;            av_dict_free(&amp;pDicts);  // Free the dictionary in case of an error&#xA;            throw std::runtime_error("Could not open source.");&#xA;        }&#xA;    }&#xA;    catch (const std::exception&amp; e)&#xA;    {&#xA;        std::cerr &lt;&lt; "Exception: " &lt;&lt; e.what() &lt;&lt; std::endl;&#xA;        return false;&#xA;    }&#xA;&#xA;    try&#xA;    {&#xA;        rc = avformat_find_stream_info(pFormatCtx, NULL);&#xA;        if (rc &lt; 0)&#xA;        {&#xA;            throw std::runtime_error("Could not find stream information.");&#xA;        }&#xA;        pVideoStream = -1;&#xA;        for (size_t v = 0; v &lt; pFormatCtx->nb_streams; &#x2B;&#x2B;v)&#xA;        {&#xA;            if (pFormatCtx->streams[v]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)&#xA;            {&#xA;                pVideoStream = static_cast<int>(v);&#xA;                AVRational rational = pFormatCtx->streams[pVideoStream]->avg_frame_rate;&#xA;                pFPS = 1.0 / ((double)rational.num / (double)(rational.den));&#xA;                break;&#xA;            }&#xA;        }&#xA;        if (pVideoStream &lt; 0)&#xA;        {&#xA;            throw std::runtime_error("Could not find video stream.");&#xA;        }&#xA;&#xA;        const AVCodec* pCodec = avcodec_find_decoder(pFormatCtx->streams[pVideoStream]->codecpar->codec_id);&#xA;        if (!pCodec)&#xA;        {&#xA;            throw std::runtime_error("Unsupported codec!");&#xA;        }&#xA;        pCodecCtx = avcodec_alloc_context3(pCodec);&#xA;        if (!pCodecCtx)&#xA;        {&#xA;            throw std::runtime_error("Failed to allocate AVCodecContext.");&#xA;        }&#xA;        rc = avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[pVideoStream]->codecpar);&#xA;        if (rc != 0)&#xA;        {&#xA;            throw std::runtime_error("Could not copy codec context.");&#xA;        }&#xA;        rc = avcodec_open2(pCodecCtx, pCodec, NULL);&#xA;        if (rc &lt; 0)&#xA;        {&#xA;            throw std::runtime_error("Could not open codec.");&#xA;        }&#xA;        pFrame = av_frame_alloc();&#xA;        if (!pFrame)&#xA;        {&#xA;            throw std::runtime_error("Could not allocate frame.");&#xA;        }&#xA;        pSwsCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BILINEAR, NULL, NULL, NULL);&#xA;        if (!pSwsCtx)&#xA;        {&#xA;            throw std::runtime_error("Failed to allocate SwsContext.");&#xA;        }&#xA;        pPacket = av_packet_alloc();&#xA;        if (!pPacket)&#xA;        {&#xA;            throw std::runtime_error("Could not allocate AVPacket.");&#xA;        }&#xA;        pBuffer = (uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height, 1));&#xA;        if (!pBuffer)&#xA;        {&#xA;            throw std::runtime_error("Could not allocate buffer.");&#xA;        }&#xA;        pPict = av_frame_alloc();&#xA;        if (!pPict)&#xA;        {&#xA;            throw std::runtime_error("Could not allocate frame.");&#xA;        }&#xA;        av_image_fill_arrays(pPict->data, pPict->linesize, pBuffer, AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height, 1);&#xA;    }&#xA;    catch (const std::exception&amp; e)&#xA;    {&#xA;        std::cerr &lt;&lt; "Exception: " &lt;&lt; e.what() &lt;&lt; std::endl;&#xA;        return false;&#xA;    }&#xA;&#xA;    return true;&#xA;}&#xA;&#xA;ryMediaSource::mediaSourceParams ryMediaSource::ryGetMediaSourceFrame()&#xA;{&#xA;    mediaSourceParams msp = { 0, 0, 0, 0.0, nullptr };&#xA;    char errbuf[AV_ERROR_MAX_STRING_SIZE];&#xA;&#xA;    std::lock_guard lock(pMutex);&#xA;    if (av_read_frame(pFormatCtx, pPacket) >= 0)&#xA;    {&#xA;        if (pPacket->stream_index == pVideoStream)&#xA;        {&#xA;            int ret = avcodec_send_packet(pCodecCtx, pPacket);&#xA;            if (ret &lt; 0)&#xA;            {&#xA;                av_strerror(ret, errbuf, sizeof(errbuf));&#xA;                std::cerr &lt;&lt; "Error sending packet for avcodec_send_packet: " &lt;&lt; errbuf &lt;&lt; std::endl;&#xA;&#xA;                std::cerr &lt;&lt; "avcodec_flush_buffers " &lt;&lt; errbuf &lt;&lt; std::endl;&#xA;                avcodec_flush_buffers(pCodecCtx);&#xA;                // Handle specific error cases&#xA;                if (ret == AVERROR(EAGAIN))&#xA;                {&#xA;                    std::cerr &lt;&lt; "EAGAIN indicates that more input is required" &lt;&lt; std::endl;&#xA;                }&#xA;                else if (ret == AVERROR_EOF)&#xA;                {&#xA;                    std::cerr &lt;&lt; "AVERROR_EOF indicates that the encoder has been fully flushed" &lt;&lt; std::endl;&#xA;                }&#xA;                else&#xA;                {&#xA;                    //std::cerr &lt;&lt; "avcodec_flush_buffers " &lt;&lt; errbuf &lt;&lt; std::endl;&#xA;                    // For other errors, you may choose to flush the codec context and continue decoding.&#xA;                    //avcodec_flush_buffers(pCodecCtx);&#xA;                }&#xA;            }&#xA;            ret = avcodec_receive_frame(pCodecCtx, pFrame);&#xA;            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)&#xA;            {&#xA;                av_strerror(ret, errbuf, sizeof(errbuf));&#xA;&#xA;                std::cerr &lt;&lt; "Error receiving packet for avcodec_receive_frame: " &lt;&lt; errbuf &lt;&lt; std::endl;&#xA;&#xA;&#xA;                // EAGAIN indicates that more frames are needed or EOF is reached.&#xA;                // You may choose to break out of the loop or handle it based on your application&#x27;s logic.&#xA;&#xA;                return msp;&#xA;            }&#xA;            else if (ret &lt; 0)&#xA;            {&#xA;                av_strerror(ret, errbuf, sizeof(errbuf));&#xA;                std::cerr &lt;&lt; "Error receiving frame for avcodec_receive_frame: " &lt;&lt; errbuf &lt;&lt; std::endl;&#xA;                // Optionally, handle specific error cases&#xA;                if (ret == AVERROR(EINVAL))&#xA;                {&#xA;                    std::cerr &lt;&lt; "EINVAL indicates that more input is required" &lt;&lt; std::endl;&#xA;&#xA;                    //break;&#xA;                }&#xA;                else&#xA;                {&#xA;                    std::cerr &lt;&lt; "For other errors" &lt;&lt; std::endl;&#xA;&#xA;                    //break;&#xA;                }&#xA;            }&#xA;            // Move memory allocation outside the loop if frame size is constant&#xA;            size_t bufferSize = static_cast(pPict->linesize[0]) * pCodecCtx->height;&#xA;            msp.frame = new unsigned char[bufferSize];&#xA;            msp.lsize = pPict->linesize[0];&#xA;            msp.sx = pCodecCtx->width;&#xA;            msp.sy = pCodecCtx->height;&#xA;            msp.fps = pFPS;&#xA;            sws_scale(pSwsCtx, (uint8_t const* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pPict->data, pPict->linesize);&#xA;            std::memcpy(msp.frame, pBuffer, bufferSize);&#xA;            //delete[] msp.frame;&#xA;        }&#xA;&#xA;        // Unref packet for non-video streams&#xA;        av_packet_unref(pPacket);&#xA;    }&#xA;&#xA;    return msp;&#xA;}&#xA;&#xA;main.cpp&#xA;&#xA;std::vector streams =&#xA;{&#xA;    {"rtsp://1},&#xA;    {"rtsp://2},&#xA;    {"rtsp://3},&#xA;    {"rtsp://4},&#xA;};&#xA;&#xA;std::vector<rymediasource> mediaSources;&#xA;&#xA;void main()&#xA;{&#xA;    int key = 0;&#xA;    int channel = 0;&#xA;    std::vector streamFrame(streams.size());&#xA;    ryMediaSource::mediaSourceParams msp = { 0, 0, 0, 0.0, nullptr };&#xA;&#xA;    for (const auto&amp; stream : streams)&#xA;    {&#xA;        mediaSources.emplace_back(); // Create a new instance for each stream&#xA;    }&#xA;    for (size_t s = 0; s &lt; streams.size(); s&#x2B;&#x2B;)&#xA;    {&#xA;        try&#xA;        {&#xA;            mediaSources[s].ryOpenMediaSource(streams[s]);&#xA;        }&#xA;        catch (const std::exception&amp; e)&#xA;        {&#xA;            std::cerr &lt;&lt; "Error initializing stream " &lt;&lt; s &lt;&lt; ": " &lt;&lt; e.what() &lt;&lt; std::endl;&#xA;        }&#xA;    }&#xA;&#xA;    cv::namedWindow("ryInferenceServer", cv::WINDOW_FREERATIO);&#xA;    cv::resizeWindow("ryInferenceServer", 640, 480);&#xA;    cv::moveWindow("ryInferenceServer", 0, 0);&#xA;    for (;;)&#xA;    {&#xA;        for (size_t st = 0; st &lt; mediaSources.size(); &#x2B;&#x2B;st)&#xA;        {&#xA;            msp = mediaSources[st].ryGetMediaSourceFrame();&#xA;            if (msp.frame != nullptr)&#xA;            {&#xA;                cv::Mat preview;&#xA;                cv::Mat frame(msp.sy, msp.sx, CV_8UC3, msp.frame, msp.lsize);&#xA;                cv::resize(frame, preview, cv::Size(640, 480));&#xA;                if (!frame.empty())&#xA;                {&#xA;                    try&#xA;                    {&#xA;                        streamFrame[st] = frame.clone();&#xA;                        if (channel == st)&#xA;                        {&#xA;                            cv::imshow("ryInferenceServer", preview);&#xA;                            key = cv::waitKeyEx(1);&#xA;                            if (key == LEFT_KEY)&#xA;                            {&#xA;                                channel--;&#xA;                                if (channel &lt; 0)&#xA;                                    channel = 0;&#xA;                            }&#xA;                            if (key == RIGHT_KEY)&#xA;                            {&#xA;                                channel&#x2B;&#x2B;;&#xA;                                if (channel >= mediaSources.size())&#xA;                                    channel = mediaSources.size() - 1;&#xA;                            }&#xA;                            if (key == 27)&#xA;                                break;&#xA;                        }&#xA;                        streamFrame[st].release();&#xA;                        delete[] msp.frame;&#xA;                    }&#xA;                    catch (const std::exception&amp; e)&#xA;                    {&#xA;                        std::cerr &lt;&lt; "Exception in processing frame for stream " &lt;&lt; st &lt;&lt; ": " &lt;&lt; e.what() &lt;&lt; std::endl;&#xA;                    }&#xA;                }&#xA;                frame.release();&#xA;            }&#xA;        }&#xA;    }&#xA;}&#xA;</rymediasource></int></mutex></thread></chrono></vector></string></iostream>

    &#xA;