Esempio n. 1
0
        public void initialize(iVideoTrack videoTrack, int encodedBuffersCount)
        {
            // dbgPrintEncodedFormats();

            // Determine format of the encoded video
            sPixelFormatMP encodedFormat = videoTrack.getEncodedFormat();

            // Set format of the first and the only plane of the compressed video.
            encodedFormat.numPlanes = 1;
            encodedFormat.setPlaneFormat(0, new sPlanePixelFormat()
            {
                sizeImage = EncodedQueue.encodedVideoBufferSize(videoTrack)
            });

            // 4.5.1.5. Initialization

            // 1. Set the coded format on OUTPUT via VIDIOC_S_FMT()
            sStreamDataFormat sdf = new sStreamDataFormat()
            {
                bufferType = eBufferType.VideoOutputMPlane,
                pix_mp     = encodedFormat
            };

            device.file.call(eControlCode.S_FMT, ref sdf);

            // Logger.logVerbose( "eControlCode.S_FMT completed OK for encoded format: {0}", sdf.pix_mp );

            // 2 Allocate source (bytestream) buffers via VIDIOC_REQBUFS() on OUTPUT
            encoded = new EncodedQueue(device, encodedBuffersCount, ref encodedFormat);

            // 3 Start streaming on the OUTPUT queue via VIDIOC_STREAMON()
            device.startStreaming(eBufferType.VideoOutputMPlane);

            // Continue queuing/dequeuing bytestream buffers to/from the OUTPUT queue via VIDIOC_QBUF() and VIDIOC_DQBUF().
            // The buffers will be processed and returned to the client in order, until required metadata to configure the CAPTURE queue are found.
            // This is indicated by the decoder sending a V4L2_EVENT_SOURCE_CHANGE event with changes set to V4L2_EVENT_SRC_CH_RESOLUTION.
            eventSubscription = new EventSubscription(device);

            // Linux kernel on Pi4 appears to be too old and does not implement that spec. The event never arrives, while the encoded buffers are stuck in the Queued state.
            // For this reason, we have to deal with dynamic resolution changes instead :-(
            // WaitForResolution.wait( device, encoded, reader, waitForResolutionTimeout );
        }
Esempio 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();
        }