Ejemplo n.º 1
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();
        }
Ejemplo n.º 2
0
        // 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();
        }