/// <summary> /// Try to convert from YCbCr to RGB colors /// </summary> /// <param name="sourceColorspace">The colorspace of the luma and chroma</param> /// <param name="luma">The luma plane</param> /// <param name="blueDifferential">The blue differential (Cb) plane</param> /// <param name="redDifferential">The red differential (Cr) plane</param> /// <param name="width">The width of the frame</param> /// <param name="height">The height of the frame</param> /// <returns>An RGB plane if this function succeeds. None otherwise</returns> /// <remarks> /// FFMPEG outputs 420mpeg2 (where the chroma samples are aligned horizontally, but /// shifted a half-pixel down). /// https://msdn.microsoft.com/en-us/library/windows/desktop/dd206750(v=vs.85).aspx /// </remarks> public static Maybe<Color[][]> TryConvertFrameToRGB( ColorSpace sourceColorspace, byte[][] luma, byte[][] blueDifferential, byte[][] redDifferential, int width, int height ) { var inFrames = new YCrCbFrame { ColorSpace = sourceColorspace, Luma = luma, Cb = blueDifferential, Cr = redDifferential, Width = width, Height = height, }; if (Equals(sourceColorspace, ColorSpace.FourFourFour)) { return TryConvertYCbCr444ToRGB(inFrames); } if (Equals(sourceColorspace, ColorSpace.FourTwoTwo)) { return from horizontalUpconvert in TryConvert422To444(inFrames) select TryConvertYCbCr444ToRGB(horizontalUpconvert); } if (Equals(sourceColorspace, ColorSpace.FourTwoZeroMpeg2)) { return from verticalUpconvert in TryConvert420To422(inFrames) from horizontalUpconvert in TryConvert422To444(verticalUpconvert) select TryConvertYCbCr444ToRGB(horizontalUpconvert); } return Maybe<Color[][]>.Nothing; }
private static Maybe<YCrCbFrame> TryConvert422To444( YCrCbFrame subsampledFrames ) { var outFrames = new YCrCbFrame { ColorSpace = ColorSpace.FourTwoTwo, Luma = subsampledFrames.Luma, Cb = new byte[subsampledFrames.Height][], Cr = new byte[subsampledFrames.Height][], Width = subsampledFrames.Width, Height = subsampledFrames.Height, }; UpsampleHorizontalResolution(subsampledFrames.Cb, outFrames.Cb); UpsampleHorizontalResolution(subsampledFrames.Cr, outFrames.Cr); return outFrames.ToMaybe(); }
private static Maybe<Color[][]> TryConvertYCbCr444ToRGB( YCrCbFrame inFrame ) { try { Color[][] frame = new Color[inFrame.Height][]; for (int row = 0; row < inFrame.Height; row++) { frame[row] = new Color[inFrame.Width]; for (int col = 0; col < inFrame.Width; col++) { byte currentLuma = inFrame.Luma[row][col]; byte currentCb = inFrame.Cb[row][col]; byte currentCr = inFrame.Cr[row][col]; frame[row][col] = ConvertYUVToRGB(currentLuma, currentCb, currentCr); } } if (frame.Length != inFrame.Height || frame[0].Length != inFrame.Width) { return Maybe<Color[][]>.Nothing; } return frame.ToMaybe(); } catch (Exception) { } return Maybe<Color[][]>.Nothing; }
/// <summary> /// Vertically upconvert from 4:2:0 to 4:2:2 /// </summary> /// <param name="subsampledFrames"></param> /// <returns></returns> private static Maybe<YCrCbFrame> TryConvert420To422( YCrCbFrame subsampledFrames ) { var outFrames = new YCrCbFrame { ColorSpace = ColorSpace.FourTwoTwo, Luma = subsampledFrames.Luma, Cb = new byte[subsampledFrames.Height][], Cr = new byte[subsampledFrames.Height][], Width = subsampledFrames.Width, Height = subsampledFrames.Height, }; // Initialize all chroma planes int widthOfChromaRow = subsampledFrames.Cb[0].Length; for (int row = 0; row < outFrames.Height; row++) { outFrames.Cb[row] = new byte[widthOfChromaRow]; outFrames.Cr[row] = new byte[widthOfChromaRow]; } UpsampleVerticalResolution(subsampledFrames.Cb, outFrames.Cb); UpsampleVerticalResolution(subsampledFrames.Cr, outFrames.Cr); return outFrames.ToMaybe(); }