public void captureSetup(iVideoTrack videoTrack, int decodedBuffersCount, sDecodedVideoSize decodedSize)
        {
            this.decodedSize = decodedSize;
            if (pendingFrames.capacity != decodedBuffersCount)
            {
                pendingFrames = new PendingFrames(decodedBuffersCount);
            }

            // Set decoded format. Pi4 Linux failed to implement V4L2 stateful decoder setup workflow, instead computing everything manually, from parsed SPS.
            sPixelFormatMP sdf = computeDecodedFormat(ref decodedSize);

            device.setDataFormat(eBufferType.VideoCaptureMPlane, ref sdf);

            // Apparently, Pi4 hardware or drivers is unable to process S_SELECTION request and crop the video. Cropping it later while rendering NV12 into RGB.

            /* sSelection selection = default;
             * selection.type = eBufferType.VideoCaptureMPlane;
             * selection.target = eSelectionTarget.Compose;
             * selection.flags = eSelectionFlags.LesserOrEqual;
             * selection.rect = decodedSize.cropRect;
             * device.file.call( eControlCode.S_SELECTION, ref selection );
             * device.file.call( eControlCode.G_SELECTION, ref selection );
             * CRect selectedRect = selection.rect;
             * if( selectedRect == decodedSize.cropRect )
             *      Logger.logVerbose( "Video cropping: decoded size {0}, cropped to {1}", decodedSize.size, selectedRect );
             * else
             *      Logger.logInfo( "Video cropping: decoded size {0}, asked to crop to {1}, GPU driver replaced with {2}", decodedSize.size, decodedSize.cropRect, selectedRect ); */

            sdf     = device.getDataFormat(eBufferType.VideoCaptureMPlane);
            decoded = new DecodedQueue(device, decodedBuffersCount);
            // decoded.exportTextures( renderDev, device, ref sdf );

            // Start streaming of the output queue
            device.startStreaming(eBufferType.VideoCaptureMPlane);
        }
        public void Dispose()
        {
            eventSubscription?.Dispose();

            // dbgSaveTga?.Dispose();
            decoded?.Dispose();
            decoded = null;

            encoded?.Dispose();
            encoded = null;
        }
Exemple #3
0
        public DecoderThread(VideoDevice device, iVideoTrackReader reader, EncodedQueue encoded, DecodedQueue decoded, int shutdownEvent, iDecoderEvents eventsSink,
                             iAudioTrackReader audioReader, Audio.iDecoderQueues audioQueue)
        {
            this.device        = device;
            this.reader        = reader;
            this.encoded       = encoded;
            this.decoded       = decoded;
            this.shutdownEvent = shutdownEvent;
            this.audioReader   = audioReader;
            this.audioQueue    = audioQueue;

            // Enqueue decoded buffers
            decoded.enqueueAll();

            this.eventsSink = eventsSink;
            seekEventHandle = EventHandle.create();

            // Remaining work is done in the thread
            thread = new Thread(threadMain);
            thread.IsBackground = true;
            thread.Name         = "Media player thread";
            Logger.logInfo("Launching the video decoding thread");
            thread.Start();
        }
        // Called on decoder thread
        void iDecoderEvents.onDynamicResolutionChange()
        {
            sSelection selection = default;

            selection.type   = eBufferType.VideoCaptureMPlane;
            selection.target = eSelectionTarget.Compose;
            device.file.call(eControlCode.G_SELECTION, ref selection);
            // Logger.logInfo( "selection: {0}", selection );  // Appears to be correct, i.e. matches what's in the PPS of the video
            if (selection.rect != decodedSize.cropRect)
            {
                throw new ApplicationException($"Linux failed to decode SPS from the video; SPS says the crop rectangle is { decodedSize.cropRect }, Linux decoded as { selection.rect }");
            }

            sStreamDataFormat sdf = new sStreamDataFormat {
                bufferType = eBufferType.VideoCaptureMPlane
            };

            device.file.call(eControlCode.G_FMT, ref sdf);
            Logger.logVerbose("Automatically selected format: {0}", sdf);
            decodedPixelFormat = sdf.pix_mp;
            colorFormat        = sdf.pix_mp.colorFormat();
            Logger.logInfo("Dynamic resolution change: {0}", colorFormat);
            return;

            // The following code causes endless loop of resolution changes, despite nothing being changed, really

            // state = eDecoderState.DrainRezChange;

            // The setup workflow in that V4L spec is BS, unfortunately :-(

            device.stopStreaming(eBufferType.VideoCaptureMPlane);
            int decodedBuffersCount = decoded.buffersCount;

            decoded.Dispose();
            decoded = null;

            sImageFormatDescription format = device.findOutputFormat();

            Logger.logVerbose("Picked the format \"{0}\", {1}, flags {2}", format.description, format.pixelFormat, format.flags);


            // Destroy the old decoded buffers
            sRequestBuffers rbDecoded = new sRequestBuffers()
            {
                type   = eBufferType.VideoCaptureMPlane,
                memory = eMemory.MemoryMap
            };

            device.file.call(eControlCode.REQBUFS, ref rbDecoded);

            // Fix a few things there
            sdf.pix_mp.pixelFormat  = ePixelFormat.NV12;            // This one is actually pre-selected, prolly because of the initial one we set in the captureSetup method
            sdf.pix_mp.quantization = eQuantization.FullRange;      // Linux defaults to limited range, not what we want.
            device.file.call(eControlCode.S_FMT, ref sdf);
            // Logger.logVerbose( "Set format: {0}", sdf );

            // Create new set of decoded buffers, same count as before
            decoded = new DecodedQueue(device, decodedBuffersCount);

            // Finally, resume the video
            device.startStreaming(eBufferType.VideoCaptureMPlane);
            decoded.enqueueAll();
        }