unsafe static void Main(string[] args) { ConfirmQuickSyncReadiness.HaltIfNotReady(); Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory; // keep ascending directories until 'media' folder is found for (int i = 0; i < 10 && !Directory.Exists("Media"); i++) { Directory.SetCurrentDirectory(".."); } Directory.SetCurrentDirectory("Media"); CodecId codecId = CodecId.MFX_CODEC_JPEG; FourCC fourcc = FourCC.UYVY; // supported: RGB4, YUY2 NV12 [UYVY through tricks! see below] mfxIMPL impl = mfxIMPL.MFX_IMPL_AUTO; int width, height; string inFilename; //inFilename = "BigBuckBunny_320x180." + fourcc + ".yuv"; width = 320; height = 180; inFilename = "BigBuckBunny_1920x1080." + fourcc + ".yuv"; width = 1920; height = 1080; string outFilename = Path.ChangeExtension(inFilename, "enc.jpeg"); Console.WriteLine("Working directory: {0}", Environment.CurrentDirectory); Console.WriteLine("Input filename: {0}", inFilename); Console.WriteLine("Input width: {0} Input height: {1}", width, height); if (!File.Exists(inFilename)) { Console.WriteLine("Input file not found."); Console.WriteLine("Please let Decoder1 run to completion to create input file"); Console.WriteLine("Press any key to exit."); Console.ReadKey(); return; } Stream infs, outfs; BenchmarkTimer bt = null; #if !ENABLE_BENCHMARK infs = File.Open(inFilename, FileMode.Open); outfs = File.Open(outFilename, FileMode.Create); #else // delete this code for most simple example // * Benchmark Mode * // this block does a couple things: // 1. causes the file to be pre-read into memory so we are not timing disk reads. // 2. replaces the output stream with a NullStream so nothing gets written to disk. // 3. Starts the timer for benchmarking // this pre-reads file into memory for benchmarking long maximumMemoryToAllocate = (long)4L * 1024 * 1024 * 1024; Console.WriteLine("Pre-reading input"); infs = new PreReadLargeMemoryStream(File.Open(inFilename, FileMode.Open), maximumMemoryToAllocate); Console.WriteLine("Input read"); outfs = new NullStream(); bt = new BenchmarkTimer(); bt.Start(); int minimumFrames = 4000; #endif Console.WriteLine("Output filename: {0}", Path.GetFileName((outfs as FileStream)?.Name ?? "NO OUTPUT")); Console.WriteLine(); // The encoder cannot encode UYVY, but if you are the only decoder of the JPEG // files, you can encode UYVY as YUY2 and everything is good. if (fourcc == FourCC.UYVY) { fourcc = FourCC.YUY2; } mfxVideoParam mfxEncParams = new mfxVideoParam(); mfxEncParams.mfx.CodecId = codecId; mfxEncParams.mfx.TargetUsage = TargetUsage.MFX_TARGETUSAGE_BALANCED; //mfxEncParams.mfx.TargetKbps = 2000; //mfxEncParams.mfx.RateControlMethod = RateControlMethod.MFX_RATECONTROL_VBR; mfxEncParams.mfx.Quality = 90; mfxEncParams.mfx.Interleaved = 1; mfxEncParams.mfx.FrameInfo.FrameRateExtN = 30; mfxEncParams.mfx.FrameInfo.FrameRateExtD = 1; mfxEncParams.mfx.FrameInfo.FourCC = fourcc; switch (fourcc) { case FourCC.NV12: case FourCC.YV12: mfxEncParams.mfx.FrameInfo.ChromaFormat = ChromaFormat.MFX_CHROMAFORMAT_YUV420; break; case FourCC.YUY2: mfxEncParams.mfx.FrameInfo.ChromaFormat = ChromaFormat.MFX_CHROMAFORMAT_YUV422V; // fatal on SKYLAKE! mfxEncParams.mfx.FrameInfo.ChromaFormat = ChromaFormat.MFX_CHROMAFORMAT_YUV422; break; case FourCC.RGB4: mfxEncParams.mfx.FrameInfo.ChromaFormat = ChromaFormat.MFX_CHROMAFORMAT_YUV444; break; default: Trace.Assert(false); break; } mfxEncParams.mfx.FrameInfo.PicStruct = PicStruct.MFX_PICSTRUCT_PROGRESSIVE; mfxEncParams.mfx.FrameInfo.CropX = 0; mfxEncParams.mfx.FrameInfo.CropY = 0; mfxEncParams.mfx.FrameInfo.CropW = (ushort)width; mfxEncParams.mfx.FrameInfo.CropH = (ushort)height; // Width must be a multiple of 16 // Height must be a multiple of 16 in case of frame picture and a multiple of 32 in case of field picture mfxEncParams.mfx.FrameInfo.Width = QuickSyncStatic.ALIGN16(width); mfxEncParams.mfx.FrameInfo.Height = QuickSyncStatic.AlignHeightTo32or16(height, mfxEncParams.mfx.FrameInfo.PicStruct); mfxEncParams.IOPattern = IOPattern.MFX_IOPATTERN_IN_SYSTEM_MEMORY; // must be 'in system memory' mfxEncParams.AsyncDepth = 4; // Pipeline depth. Best at 4 mfxEncParams.mfx.FrameInfo.Width = QuickSyncStatic.ALIGN32(width); mfxEncParams.mfx.FrameInfo.Height = QuickSyncStatic.ALIGN32(height); BitStreamChunk bsc = new BitStreamChunk(); //where we receive compressed frame data ILowLevelEncoder encoder = new LowLevelEncoder(mfxEncParams, impl); //ILowLevelEncoder encoder = new LowLevelEncoder(mfxEncParams, impl); string impltext = QuickSyncStatic.ImplementationString(encoder.session); Console.WriteLine("Implementation = {0}", impltext); // not needed for YUY2 encoding //var formatConverter = new NV12FromXXXXConverter(fileFourcc, width, height); int inputFrameLength = width * height * VideoUtility.GetBitsPerPixel(fourcc) / 8; byte[] uncompressed = new byte[inputFrameLength]; int count = 0; // we do not call encoder.LockFrame() and encoder.UnlockFrame() as this example is // for system memory. while (infs.Read(uncompressed, 0, inputFrameLength) == inputFrameLength) { int ix = encoder.GetFreeFrameIndex(); //this call relys locks in authoritative array of surf //formatConverter.ConvertToNV12FrameSurface(ref encoder.Frames[ix], uncompressed, 0); mfxFrameSurface1 *f = (mfxFrameSurface1 *)encoder.Frames[ix]; switch (fourcc) { case FourCC.NV12: Trace.Assert(f->Data.Pitch == width * 1); fixed(byte *aa = &uncompressed[0]) FastMemcpyMemmove.memcpy(f->Data.Y, (IntPtr)aa, height * width); fixed(byte *aa = &uncompressed[height * width]) FastMemcpyMemmove.memcpy(f->Data.UV, (IntPtr)aa, height / 2 * width); break; case FourCC.YUY2: Trace.Assert(f->Data.Pitch == width * 2); fixed(byte *aa = &uncompressed[0]) FastMemcpyMemmove.memcpy(f->Data.Y, (IntPtr)aa, height * width * 2); break; default: Trace.Assert(false); break; } encoder.EncodeFrame(ix, ref bsc); if (bsc.bytesAvailable > 0) { outfs.Write(bsc.bitstream, 0, bsc.bytesAvailable); if (++count % 100 == 0) { Console.Write("Frame {0}\r", count); } } #if ENABLE_BENCHMARK // delete this code for most simple example if (infs.Position + inputFrameLength - 1 >= infs.Length) { infs.Position = 0; } if (count >= minimumFrames) { break; } #endif } while (encoder.Flush(ref bsc)) { if (bsc.bytesAvailable > 0) { outfs.Write(bsc.bitstream, 0, bsc.bytesAvailable); if (++count % 100 == 0) { Console.Write("Frame {0}\r", count); } } } if (bt != null) { bt.StopAndReport(count, infs.Position, outfs.Position); } infs.Close(); outfs.Close(); encoder.Dispose(); Console.WriteLine("Encoded {0} frames", count); // make sure program always waits for user, except F5-Release run if (Debugger.IsAttached || Environment.GetEnvironmentVariable("VisualStudioVersion") == null) { Console.WriteLine("done - press a key to exit"); Console.ReadKey(); } }
/// <summary> /// <para>Convert a raw frame to NV12.</para> /// <para>Used to convert fourcc formats to NV12.</para> /// /// </summary> /// <param name="srcFourcc">One of NV12 RGB3 RGB4 UYVY YUY2 YV12 BGR3 BGR4 P411 P422 I420_IYUV</param> /// <param name="nv12pitch">output pitch in bytes</param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="inFrameptr"></param> /// <param name="nv12">Y output plane destination</param> /// <param name="nv12uv">UV output plane destination</param> public unsafe void ConvertToNV12FrameSurface(FourCC srcFourcc, int nv12pitch, int width, int height, byte *inFrameptr, byte *nv12, byte *nv12uv) { NativeResizeConvertStatus sts = NativeResizeConvertStatus.NativeStatusNoErr; roisizea.height = height; roisizea.width = width; switch (srcFourcc) { //case FourCC.A2RGB10: // break; //case FourCC.ARGB16: // break; case FourCC.NV12: //memmove(nv12, inFrameptr, height * width); //memmove(nv12uv, inFrameptr + height * width, height * width / 2); for (int j = 0; j < height; j++) { // Marshal.Copy(uncompressed, i * framelen + j * w, e.Frames[ix].Data.Y + e.Frames[ix].Data.Pitch * j, w); FastMemcpyMemmove.memcpy(nv12 + nv12pitch * j, inFrameptr + width * j, width); } for (int j = 0; j < height / 2; j++) { FastMemcpyMemmove.memcpy(nv12uv + nv12pitch * j, inFrameptr + width * height + width * j, width); } // Marshal.Copy(uncompressed, i * framelen + j * w + h * w, e.Frames[ix].Data.UV + e.Frames[ix].Data.Pitch * j, w); break; //case FourCC.NV16: // break; //case FourCC.P010: // break; //case FourCC.P210: // break; //case FourCC.P8: // break; //case FourCC.P8_TEXTURE: // break; //case FourCC.R16: // break; case FourCC.BGR3: sts = NV12Convert.BGR3ToNV12(inFrameptr, width * 3, nv12, nv12pitch, nv12uv, nv12pitch, roisizea); break; case FourCC.BGR4: // this was not supported originally due to lack of support in intel IPP sts = NV12Convert.BGR4ToNV12(inFrameptr, width * 4, nv12, nv12pitch, nv12uv, nv12pitch, roisizea); break; case FourCC.IYUV: pointers[0] = inFrameptr; pointers[1] = inFrameptr + height * width; pointers[2] = inFrameptr + height * width + height * width / 2 / 2; intarr[0] = width; intarr[1] = width / 2; intarr[2] = width / 2; fixed(byte **p1 = pointers) fixed(int *p2 = intarr) { sts = NV12Convert.IYUVToNV12(p1, p2, nv12, nv12pitch, nv12uv, nv12pitch, roisizea); } break; case FourCC.P411: pointers[0] = inFrameptr; pointers[1] = inFrameptr + height * width; pointers[2] = inFrameptr + height * width + height * width / 4; intarr[0] = width; intarr[1] = width / 4; intarr[2] = width / 4; fixed(byte **p1 = pointers) fixed(int *p2 = intarr) { sts = NV12Convert.P411ToNV12(p1, p2, nv12, nv12pitch, nv12uv, nv12pitch, roisizea); } break; case FourCC.P422: pointers[0] = inFrameptr; pointers[1] = inFrameptr + height * width; pointers[2] = inFrameptr + height * width + height * width / 2; intarr[0] = width; intarr[1] = width / 2; intarr[2] = width / 2; fixed(byte **p1 = pointers) fixed(int *p2 = intarr) { sts = NV12Convert.P422ToNV12(p1, p2, nv12, nv12pitch, nv12uv, nv12pitch, roisizea); } break; case FourCC.RGB3: sts = NV12Convert.RGB3ToNV12(inFrameptr, width * 3, nv12, nv12pitch, nv12uv, nv12pitch, roisizea); break; case FourCC.RGB4: sts = NV12Convert.RGB4ToNV12(inFrameptr, width * 4, nv12, nv12pitch, nv12uv, nv12pitch, roisizea); break; case FourCC.YUY2: sts = NV12Convert.YUY2ToNV12(inFrameptr, width * 2, nv12, nv12pitch, nv12uv, nv12pitch, roisizea); break; case FourCC.YV12: //YVU // YCbCr == YUV pointers[0] = inFrameptr; pointers[1] = inFrameptr + height * width; pointers[2] = inFrameptr + height * width + height * width / 2 / 2; intarr[0] = width; intarr[1] = width / 2; intarr[2] = width / 2; fixed(byte **p1 = pointers) fixed(int *p2 = intarr) sts = NV12Convert.YV12ToNV12(p1, p2, nv12, nv12pitch, nv12uv, nv12pitch, roisizea); break; case FourCC.UYVY: // sts = NV12Convert.ippiCbYCr422ToYCbCr420_8u_C2P2R(inFrameptr, width * 2, nv12, nv12pitch, nv12uv, nv12pitch, roisizea); sts = NV12Convert.UYVYToNV12(inFrameptr, width * 2, nv12, nv12pitch, nv12uv, nv12pitch, roisizea); break; default: break; } if (sts != NativeResizeConvertStatus.NativeStatusNoErr) { throw new Exception("FourCC convert error:" + sts.ToString()); } }
unsafe static void Main(string[] args) { ConfirmQuickSyncReadiness.HaltIfNotReady(); Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory; // keep ascending directories until 'media' folder is found for (int i = 0; i < 10 && !Directory.Exists("Media"); i++) { Directory.SetCurrentDirectory(".."); } Directory.SetCurrentDirectory("Media"); CodecId codecId = CodecId.MFX_CODEC_JPEG; FourCC fourcc = FourCC.UYVY; // supported: RGB4, YUY2 NV12 [UYVY through tricks! see below] mfxIMPL impl = mfxIMPL.MFX_IMPL_AUTO; string fourccString = fourcc.ToString().Substring(0, 4); string inFilename; //inFilename = "BigBuckBunny_320x180.UYVY.enc.jpeg"; inFilename = "BigBuckBunny_1920x1080.UYVY.enc.jpeg"; //inFilename = "BigBuckBunny_3840x2160.UYVY.enc.jpeg"; string outFilename = Path.ChangeExtension(inFilename, ".yuv"); Console.WriteLine("Working directory: {0}", Environment.CurrentDirectory); Console.WriteLine("Input filename: {0}", inFilename); Console.WriteLine(); if (!File.Exists(inFilename)) { Console.WriteLine("Input file not found. Press any key to exit."); Console.ReadKey(); return; } Stream infs, outfs; BenchmarkTimer bt = null; #if !ENABLE_BENCHMARK infs = File.Open(inFilename, FileMode.Open); outfs = File.Open(outFilename, FileMode.Create); #else // delete this code for most simple example // * Benchmark Mode * // this block does a couple things: // 1. causes the file to be pre-read into memory so we are not timing disk reads. // 2. replaces the output stream with a NullStream so nothing gets written to disk. // 3. Starts the timer for benchmarking // this pre-reads file into memory for benchmarking long maximumMemoryToAllocate = (long)4L * 1024 * 1024 * 1024; Console.WriteLine("Pre-reading input"); infs = new PreReadLargeMemoryStream(File.Open(inFilename, FileMode.Open), maximumMemoryToAllocate); Console.WriteLine("Input read"); outfs = new NullStream(); bt = new BenchmarkTimer(); bt.Start(); int minimumFrames = 4000; #endif Console.WriteLine("Output filename: {0}", Path.GetFileName((outfs as FileStream)?.Name ?? "NO OUTPUT")); Console.WriteLine(); var outIOPattern = IOPattern.MFX_IOPATTERN_OUT_SYSTEM_MEMORY; // The encoder cannot encode UYVY, but if you are the only decoder of the JPEG // files, you can encode UYVY as YUY2 and everything is good. if (fourcc == FourCC.UYVY) { fourcc = FourCC.YUY2; } mfxVideoParam decoderParameters = QuickSyncStatic.ReadFileHeaderInfo(codecId, impl, infs, outIOPattern); decoderParameters.mfx.FrameInfo.FourCC = fourcc; AssignChromaFormat(fourcc, ref decoderParameters); var decoder = new StreamDecoder(infs, decoderParameters, null, impl); #if ENABLE_BENCHMARK // delete this code for most simple example decoder.benchmarkNeverStopMode = true; #endif string impltext = QuickSyncStatic.ImplementationString(decoder.lowLevelDecoder.session); Console.WriteLine("Implementation = {0}", impltext); // not needed //var formatConverter = new NV12ToXXXXConverter(fourcc, decoder.width, decoder.height); int width = decoderParameters.mfx.FrameInfo.CropW; int height = decoderParameters.mfx.FrameInfo.CropH; var tmpbuf = new byte[width * height * 2]; int count = 0; foreach (var frame in decoder.GetFrames()) { //var frameBytes = formatConverter.ConvertFromNV12(frame.Data); // Convert to format requested Trace.Assert(frame.Data.Pitch == width * 2); // yuy2 only fixed(byte *aa = &tmpbuf[0]) FastMemcpyMemmove.memcpy((IntPtr)aa, frame.Data.Y, height * width * 2); outfs.Write(tmpbuf, 0, tmpbuf.Length); if (++count % 100 == 0) { Console.Write("Frame {0}\r", count); } #if ENABLE_BENCHMARK // delete this code for most simple example if (count > minimumFrames) { break; } #endif } if (bt != null) { bt.StopAndReport(count, infs.Position, outfs.Position); } infs.Close(); outfs.Close(); Console.WriteLine("Decoded {0} frames", count); // make sure program always waits for user, except F5-Release run if (Debugger.IsAttached || Environment.GetEnvironmentVariable("VisualStudioVersion") == null) { Console.WriteLine("done - press a key to exit"); Console.ReadKey(); } }
/// <summary> /// Convert an NV12 frame to another fourcc format /// </summary> /// <param name="destFourcc">One of NV12 RGB3 RGB4 UYVY YUY2 YV12 BGR3 P411 P422 I420_IYUV</param> /// <param name="Y">Y plane of NV12 input</param> /// <param name="UV">UV plane of NV12 input</param> /// <param name="outputFramePtr">where output frame goes</param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="outputLen"></param> /// <param name="srcPitch">Pitch of the source NV12</param> /// <param name="dstPitch">Pitch of the dest frame</param> /// <param name="alpha">Only used for formats with sn alpha plane: RGB4, ...</param> public unsafe void ConvertFromNV12(FourCC destFourcc, byte *Y, byte *UV, byte *outputFramePtr, int width, int height, int outputLen, int srcPitch = 0, int dstPitch = 0, byte alpha = 255) { int bitsPerPixel = VideoUtility.GetBitsPerPixel(destFourcc); // int dstpitch = bitsPerPixel * width / 8; int compactFrameSize = width * height * bitsPerPixel / 8; Trace.Assert(outputLen == compactFrameSize); //byte* nv12uv = nv12 + width * height; roisize.height = height; roisize.width = width; NativeResizeConvertStatus sts = NativeResizeConvertStatus.NativeStatusNoErr; if (srcPitch == 0) { srcPitch = width * 1; } if (dstPitch == 0) { dstPitch = width * VideoUtility.GetPackedPitchMultiplier(destFourcc); } switch (destFourcc) { case FourCC.BGR3: sts = NV12Convert.NV12ToBGR3(Y, srcPitch, UV, srcPitch, outputFramePtr, dstPitch, roisize); break; case FourCC.BGR4: sts = NV12Convert.NV12ToBGR4(Y, srcPitch, UV, srcPitch, outputFramePtr, dstPitch, roisize, alpha); break; case FourCC.RGB4: sts = NV12Convert.NV12ToRGB4(Y, srcPitch, UV, srcPitch, outputFramePtr, dstPitch, roisize, alpha); break; case FourCC.RGB3: sts = NV12Convert.NV12ToRGB3(Y, srcPitch, UV, srcPitch, outputFramePtr, dstPitch, roisize); break; case FourCC.YUY2: sts = NV12Convert.NV12ToYUY2(Y, srcPitch, UV, srcPitch, outputFramePtr, dstPitch, roisize); break; case FourCC.YV12: pdst[0] = outputFramePtr; // This seems wrong, backwards, maybe a bug in IPP 7.x // indicies should be 1,2 not 2,1 //manual check indicates this is what works correctly 2/22/15 pdst[2] = outputFramePtr + height * width; pdst[1] = outputFramePtr + height * width + height * width / 2 / 2; dststep[0] = dstPitch; dststep[1] = dstPitch / 2; dststep[2] = dstPitch / 2; fixed(byte **p1 = pdst) fixed(int *p2 = dststep) sts = NV12Convert.NV12ToYV12(Y, srcPitch, UV, srcPitch, p1, p2, roisize); break; case FourCC.UYVY: sts = NV12Convert.NV12ToUYVY(Y, srcPitch, UV, srcPitch, outputFramePtr, dstPitch, roisize); break; case FourCC.I420_IYUV: pdst[0] = outputFramePtr; pdst[1] = outputFramePtr + height * width; pdst[2] = outputFramePtr + height * width + height * width / 2 / 2; dststep[0] = dstPitch; dststep[1] = dstPitch / 2; dststep[2] = dstPitch / 2; fixed(byte **p1 = pdst) fixed(int *p2 = dststep) sts = NV12Convert.NV12ToYV12(Y, srcPitch, UV, srcPitch, p1, p2, roisize); break; case FourCC.P411: pdst[0] = outputFramePtr; pdst[1] = outputFramePtr + height * width; pdst[2] = outputFramePtr + height * width + height * width / 4; dststep[0] = dstPitch; dststep[1] = dstPitch / 4; dststep[2] = dstPitch / 4; fixed(byte **p1 = pdst) fixed(int *p2 = dststep) sts = NV12Convert.NV12ToP411(Y, srcPitch, UV, srcPitch, p1, p2, roisize); break; case FourCC.P422: pdst[0] = outputFramePtr; pdst[1] = outputFramePtr + height * width; pdst[2] = outputFramePtr + height * width + height * width / 2; dststep[0] = dstPitch; dststep[1] = dstPitch / 2; dststep[2] = dstPitch / 2; fixed(byte **p1 = pdst) fixed(int *p2 = dststep) sts = NV12Convert.NV12ToP422(Y, srcPitch, UV, srcPitch, p1, p2, roisize); break; case FourCC.NV12: // XXX nonono // does not work for pitch!=width !! //memmove(outputFramePtr, Y, height * width); //memmove(outputFramePtr + height * width, UV, height * width / 2); for (int i = 0; i < height; i++) { FastMemcpyMemmove.memcpy(outputFramePtr + i * dstPitch, Y + i * srcPitch, width); } outputFramePtr += height * dstPitch; for (int i = 0; i < height / 2; i++) { FastMemcpyMemmove.memcpy(outputFramePtr + i * dstPitch, UV + i * srcPitch, width); } break; default: throw new Exception("fourcc conversion not supported, contact Lime Video support for options"); } if (sts != NativeResizeConvertStatus.NativeStatusNoErr) { throw new Exception("FourCC convert error:" + sts.ToString()); } }