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; }
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(); }