public unsafe void Start()

in Sources/Media/Microsoft.Psi.Media.Linux/MediaCapture.cs [109:228]


        public unsafe void Start(Action<DateTime> notifyCompletionTime)
        {
            // notify that this is an infinite source component
            notifyCompletionTime(DateTime.MaxValue);

            this.camera = new MediaCaptureInternal(this.configuration.DeviceId);
            this.camera.Open();
            var isFormatSupported = false;
            foreach (var format in this.camera.SupportedPixelFormats())
            {
                if (format.Pixels == this.configuration.PixelFormat)
                {
                    this.camera.SetVideoFormat(this.configuration.Width, this.configuration.Height, format);
                    isFormatSupported = true;
                }
            }

            if (!isFormatSupported)
            {
                throw new ArgumentException($"Pixel format {this.configuration.PixelFormat} is not supported by the camera");
            }

            var current = this.camera.GetVideoFormat();
            if (current.Width != this.configuration.Width || current.Height != this.configuration.Height)
            {
                throw new ArgumentException($"Width/height {this.configuration.Width}x{this.configuration.Height} is not supported by the camera");
            }

            this.camera.OnFrame += (_, frame) =>
            {
                var originatingTime = this.pipeline.GetCurrentTime();

                if (this.Raw.HasSubscribers)
                {
                    var len = frame.Length;
                    using (Shared<byte[]> shared = SharedArrayPool<byte>.GetOrCreate(len))
                    {
                        Marshal.Copy(frame.Start, shared.Resource, 0, len);
                        this.Raw.Post(shared, originatingTime);
                    }
                }

                if (this.Out.HasSubscribers)
                {
                    if (this.configuration.PixelFormat == PixelFormatId.BGR24)
                    {
                        using (var sharedImage = ImagePool.GetOrCreate(this.configuration.Width, this.configuration.Height, PixelFormat.BGR_24bpp))
                        {
                            sharedImage.Resource.CopyFrom((IntPtr)frame.Start);
                            this.Out.Post(sharedImage, this.pipeline.GetCurrentTime());
                        }
                    }
                    else if (this.configuration.PixelFormat == PixelFormatId.YUYV)
                    {
                        // convert YUYV -> BGR24 (see https://msdn.microsoft.com/en-us/library/ms893078.aspx)
                        using (var sharedImage = ImagePool.GetOrCreate(this.configuration.Width, this.configuration.Height, PixelFormat.BGR_24bpp))
                        {
                            var len = (int)(frame.Length * 1.5);
                            using (Shared<byte[]> shared = SharedArrayPool<byte>.GetOrCreate(len))
                            {
                                var bytes = shared.Resource;
                                var pY = (byte*)frame.Start.ToPointer();
                                var pU = pY + 1;
                                var pV = pY + 3;
                                for (var i = 0; i < len;)
                                {
                                    int y = (*pY - 16) * 298;
                                    int u = *pU - 128;
                                    int v = *pV - 128;
                                    int r = (y + (409 * v) + 128) >> 8;
                                    int g = (y - (100 * u) - (208 * v) + 128) >> 8;
                                    int b = (y + (516 * u) + 128) >> 8;

                                    bytes[i++] = (byte)((r < 0) ? 0 : ((r > 255) ? 255 : r));
                                    bytes[i++] = (byte)((g < 0) ? 0 : ((g > 255) ? 255 : g));
                                    bytes[i++] = (byte)((b < 0) ? 0 : ((b > 255) ? 255 : b));

                                    pY += 2;

                                    y = (*pY - 16) * 298;
                                    r = (y + (409 * v) + 128) >> 8;
                                    g = (y - (100 * u) - (208 * v) + 128) >> 8;
                                    b = (y + (516 * u) + 128) >> 8;
                                    bytes[i++] = (byte)((r < 0) ? 0 : ((r > 255) ? 255 : r));
                                    bytes[i++] = (byte)((g < 0) ? 0 : ((g > 255) ? 255 : g));
                                    bytes[i++] = (byte)((b < 0) ? 0 : ((b > 255) ? 255 : b));

                                    pY += 2;
                                    pU += 4;
                                    pV += 4;
                                }

                                sharedImage.Resource.CopyFrom(bytes);
                                this.Out.Post(sharedImage, originatingTime);
                            }
                        }
                    }
                    else if (this.configuration.PixelFormat == PixelFormatId.MJPEG)
                    {
                        var decoded = SKBitmap.Decode(new UnmanagedMemoryStream((byte*)frame.Start, frame.Length));
                        if (decoded != null)
                        {
                            using (var sharedImage = ImagePool.GetOrCreate(this.configuration.Width, this.configuration.Height, PixelFormat.BGRA_32bpp))
                            {
                                sharedImage.Resource.CopyFrom(decoded.Bytes);
                                this.Out.Post(sharedImage, originatingTime);
                            }
                        }
                    }
                }

#if TEST_DROPPED_FRAMES
                System.Threading.Thread.Sleep(1000); // for testing dropped frames
#endif // TEST_DROPPED_FRAMES

                frame.Dispose(); // release back to driver!
            };

            this.camera.StreamBuffers();
        }