void GetBitstreamIfAny(ref BitStreamChunk bsc) { mfxStatus sts = 0; bsc.bytesAvailable = 0; Trace.Assert(pTasks[nFirstSyncTask].syncp.sync_ptr != null); // No more free tasks, need to sync sts = UnsafeNativeMethods.MFXVideoCORE_SyncOperation(session, pTasks[nFirstSyncTask].syncp, 60000); QuickSyncStatic.ThrowOnBadStatus(sts, "syncoper"); // sts = WriteBitStreamFrame(&pTasks[nFirstSyncTask].mfxBS, fSink); // MSDK_BREAK_ON_ERROR(g); int n = (int)pTasks[nFirstSyncTask].mfxBS.DataLength; if (bsc.bitstream == null || bsc.bitstream.Length < n) { bsc.bitstream = new byte[pTasks[nFirstSyncTask].mfxBS.MaxLength]; } Trace.Assert(pTasks[nFirstSyncTask].mfxBS.DataOffset == 0); Marshal.Copy(pTasks[nFirstSyncTask].mfxBS.Data, bsc.bitstream, 0, n); bsc.bytesAvailable = n; pTasks[nFirstSyncTask].mfxBS.DataLength = 0; pTasks[nFirstSyncTask].syncp.sync_ptr = null; nFirstSyncTask = (nFirstSyncTask + 1) % pTasks.Length; }
/// <summary> /// /// </summary> /// <param name="bsc"></param> /// <returns>true:all done, false:continue to call me</returns> public bool Flush4(ref BitStreamChunk bsc) { mfxStatus sts; bsc.bytesAvailable = 0; while (pTasks[nFirstSyncTask].syncp.sync != IntPtr.Zero) { sts = UnsafeNativeMethods.MFXVideoCORE_SyncOperation(session, pTasks[nFirstSyncTask].syncp, 60000); QuickSyncStatic.ThrowOnBadStatus(sts, "syncOper"); if (bsc.bitstream == null || bsc.bitstream.Length < pTasks[nFirstSyncTask].mfxBS.DataLength) { bsc.bitstream = new byte[pTasks[nFirstSyncTask].mfxBS.DataLength]; } Trace.Assert(pTasks[nFirstSyncTask].mfxBS.DataOffset == 0); Marshal.Copy(pTasks[nFirstSyncTask].mfxBS.Data, bsc.bitstream, 0, (int)pTasks[nFirstSyncTask].mfxBS.DataLength); bsc.bytesAvailable = (int)pTasks[nFirstSyncTask].mfxBS.DataLength; // WriteBitStreamFrame(pTasks[nFirstSyncTask].mfxBS, outbs); //MSDK_BREAK_ON_ERROR(sts); pTasks[nFirstSyncTask].syncp.sync = IntPtr.Zero; pTasks[nFirstSyncTask].mfxBS.DataLength = 0; pTasks[nFirstSyncTask].mfxBS.DataOffset = 0; nFirstSyncTask = (nFirstSyncTask + 1) % taskPoolSize; return(true); } return(false); }
//object ILowLevelEncoder.deviceSetup //{ // get // { // throw new NotImplementedException(); // } //} /// <summary>After passing all frames to be encoded you must call this to flush out bitstream in the engine.</summary> /// <param name="bitstreamChunk">Frames returned</param> /// <returns>true indicates you must keep calling me</returns> public bool Flush(ref BitStreamChunk bitstreamChunk) { bitstreamChunk.bytesAvailable = 0; if (flush1state) { flush1state = Flush1(ref bitstreamChunk); return(true); } return(Flush2(ref bitstreamChunk)); }
public unsafe void EncodeFrame(int frameIndex, ref BitStreamChunk bitstreamChunk) { bitstreamChunk.bytesAvailable = 0; var a = frameIntPtrs[frameIndex]; var sts = NativeLLEncoderUnsafeNativeMethods.NativeEncoder_EncodeFrame(h, (mfxFrameSurface1 *)a); QuickSyncStatic.ThrowOnBadStatus(sts, nameof(NativeLLEncoderUnsafeNativeMethods.NativeEncoder_EncodeFrame)); CopyOutBitstream(ref bitstreamChunk); }
bool Flush2(ref BitStreamChunk bsc) { if (pTasks[nFirstSyncTask].syncp.sync_ptr != null) { GetBitstreamIfAny(ref bsc); return(true); } else { return(false); } }
bool Flush1(ref BitStreamChunk bsc) { bsc.bytesAvailable = 0; if (GetBitstreamIfFull(ref bsc)) { return(true); } mfxStatus sts = 0; int nTaskIdx = GetFreeTaskIndex(pTasks); // Find free task Trace.Assert((int)mfxStatus.MFX_ERR_NOT_FOUND != nTaskIdx); for (;;) { // Encode a frame asychronously (returns immediately) fixed(mfxBitstream *b = &pTasks[nTaskIdx].mfxBS) fixed(mfxSyncPoint * c = &pTasks[nTaskIdx].syncp) sts = UnsafeNativeMethods.MFXVideoENCODE_EncodeFrameAsync(session, null, null, b, c); if (mfxStatus.MFX_ERR_NONE < sts && !(pTasks[nTaskIdx].syncp.sync_ptr != null)) { // Repeat the call if warning and no output if (mfxStatus.MFX_WRN_DEVICE_BUSY == sts) { Thread.Sleep(1); // Wait if device is busy, then repeat the same call } } else if (mfxStatus.MFX_ERR_NONE < sts && pTasks[nTaskIdx].syncp.sync_ptr != null) { sts = mfxStatus.MFX_ERR_NONE; // Ignore warnings if output is available break; } else { break; } } // MFX_ERR_MORE_DATA means that the input file has ended, need to go to buffering loop, exit in case of other errors //MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA); if (sts == mfxStatus.MFX_ERR_MORE_DATA) { return(false); // no more to flush here } sts = mfxStatus.MFX_ERR_NONE; //MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); QuickSyncStatic.ThrowOnBadStatus(sts, "flush1.encodeFrameAsync"); return(true); // yes, call me again, more to flush }
private void CopyOutBitstream(ref BitStreamChunk bitstreamChunk) { if (bitstreamChunk.bitstream == null) { bitstreamChunk.bitstream = new byte[shared->maxbuflen]; } if (shared->buflen > 0) { Marshal.Copy((IntPtr)shared->buf, bitstreamChunk.bitstream, 0, shared->buflen); } bitstreamChunk.bytesAvailable = shared->buflen; }
bool GetBitstreamIfFull(ref BitStreamChunk bsc) { bsc.bytesAvailable = 0; int nTaskIdx = GetFreeTaskIndex(pTasks); // Find free task if ((int)mfxStatus.MFX_ERR_NOT_FOUND == nTaskIdx) { GetBitstreamIfAny(ref bsc); return(true); } return(false); }
bool Flush2(ref BitStreamChunk bitstreamChunk) { bitstreamChunk.bytesAvailable = 0; var sts = NativeLLEncoderUnsafeNativeMethods.NativeEncoder_Flush2(h); if (sts == mfxStatus.MFX_ERR_MORE_DATA) { return(false); } QuickSyncStatic.ThrowOnBadStatus(sts, nameof(NativeLLEncoderUnsafeNativeMethods.NativeEncoder_Flush2)); CopyOutBitstream(ref bitstreamChunk); return(true); }
/// <summary>Encodes a frame.</summary> /// <param name="frameIndex">Index of the frame to encode.</param> /// <param name="bitStreamChunk">Output frames bitstream data, if available</param> public void EncodeFrame(int frameIndex, ref BitStreamChunk bitStreamChunk) { mfxStatus sts = 0; bitStreamChunk.bytesAvailable = 0; GetBitstreamIfFull(ref bitStreamChunk); // int nEncSurfIdx = 0; int nTaskIdx = GetFreeTaskIndex(pTasks); // Find free task Trace.Assert((int)mfxStatus.MFX_ERR_NOT_FOUND != nTaskIdx); //int nsource = 0; //var buf = new byte[pTasks[0].mfxBS.MaxLength]; // // Stage 1: Main encoding loop // //if (mfxStatus.MFX_ERR_NONE <= sts || mfxStatus.MFX_ERR_MORE_DATA == sts) //{ // } // else // { //nEncSurfIdx = GetFreeSurfaceIndex(pmfxSurfaces); // Find free frame surface //MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nEncSurfIdx, MFX_ERR_MEMORY_ALLOC); //Trace.Assert(nEncSurfIdx != (int)mfxStatus.MFX_ERR_NOT_FOUND); // Surface locking required when read/write D3D surfaces //sts = mfxAllocator.Lock(mfxAllocator.pthis, pmfxSurfaces[nEncSurfIdx]->Data.MemId, &(pmfxSurfaces[nEncSurfIdx]->Data)); //MSDK_BREAK_ON_ERROR(sts); // sts = LoadRawFrame(pmfxSurfaces[nEncSurfIdx], fSource); // MSDK_BREAK_ON_ERROR(sts); // from the prototype, we just copy the frame data from a byte array, // but in this class we are passed a prepared frame. //int pfs = 320 * 180 * 3 / 2; //if (nsource * pfs >= yuv.Length) // break; //int stride = pmfxSurfaces[nEncSurfIdx].Data.Pitch; //for (int i = 0; i < h; i++) // Marshal.Copy(yuv, nsource * pfs + i * w, pmfxSurfaces[nEncSurfIdx].Data.Y + stride * i, w); //for (int i = 0; i < h / 2; i++) // Marshal.Copy(yuv, nsource * pfs + i * w + h * w, pmfxSurfaces[nEncSurfIdx].Data.UV + stride * i, w); //sts = mfxAllocator.Unlock(mfxAllocator.pthis, pmfxSurfaces[nEncSurfIdx]->Data.MemId, &(pmfxSurfaces[nEncSurfIdx]->Data)); //MSDK_BREAK_ON_ERROR(sts); // Frames[nEncSurfIdx] = frame; for (;;) { // Encode a frame asychronously (returns immediately) fixed(mfxFrameSurface1 *a = &Frames[frameIndex]) fixed(mfxBitstream * b = &pTasks[nTaskIdx].mfxBS) fixed(mfxSyncPoint * c = &pTasks[nTaskIdx].syncp) sts = UnsafeNativeMethods.MFXVideoENCODE_EncodeFrameAsync(session, null, a, b, c); if (mfxStatus.MFX_ERR_NONE < sts && !(pTasks[nTaskIdx].syncp.sync_ptr != null)) { // Repeat the call if warning and no output if (mfxStatus.MFX_WRN_DEVICE_BUSY == sts) { Thread.Sleep(1); // Wait if device is busy, then repeat the same call } } else if (mfxStatus.MFX_ERR_NONE < sts && pTasks[nTaskIdx].syncp.sync_ptr != null) { sts = mfxStatus.MFX_ERR_NONE; // Ignore warnings if output is available break; } else if (mfxStatus.MFX_ERR_NOT_ENOUGH_BUFFER == sts) { Trace.Assert(false); // Allocate more bitstream buffer memory here if needed... break; } else { break; } } // } // MFX_ERR_MORE_DATA means that the input file has ended, need to go to buffering loop, exit in case of other errors //MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA); if (sts == mfxStatus.MFX_ERR_MORE_DATA) { sts = mfxStatus.MFX_ERR_NONE; } //MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); QuickSyncStatic.ThrowOnBadStatus(sts, "encodeFrameAsync"); return; }
/// <summary>Get frames during 2nd stage of flushing</summary> /// <param name="bitStreamChunk">A single frame</param> /// <returns>true if you should continue to call this method, false if you must go to the next phase.</returns> public bool Flush3(ref BitStreamChunk bitStreamChunk) { bitStreamChunk.bytesAvailable = 0; //////// mfxStatus sts = mfxStatus.MFX_ERR_NONE; // // Stage 4: Retrieve the buffered encoded frames // if (mfxStatus.MFX_ERR_NONE <= sts) { int nTaskIdx = GetFreeTaskIndex(pTasks, taskPoolSize); // Find free task if ((int)mfxStatus.MFX_ERR_NOT_FOUND == nTaskIdx) { // No more free tasks, need to sync sts = UnsafeNativeMethods.MFXVideoCORE_SyncOperation(session, pTasks[nFirstSyncTask].syncp, 60000); QuickSyncStatic.ThrowOnBadStatus(sts, "syncOper"); if (bitStreamChunk.bitstream == null || bitStreamChunk.bitstream.Length < pTasks[nFirstSyncTask].mfxBS.DataLength) { bitStreamChunk.bitstream = new byte[pTasks[nFirstSyncTask].mfxBS.DataLength]; } Trace.Assert(pTasks[nFirstSyncTask].mfxBS.DataOffset == 0); Marshal.Copy(pTasks[nFirstSyncTask].mfxBS.Data, bitStreamChunk.bitstream, 0, (int)pTasks[nFirstSyncTask].mfxBS.DataLength); bitStreamChunk.bytesAvailable = (int)pTasks[nFirstSyncTask].mfxBS.DataLength; // WriteBitStreamFrame(pTasks[nFirstSyncTask].mfxBS, outbs); //MSDK_BREAK_ON_ERROR(sts); pTasks[nFirstSyncTask].syncp.sync = IntPtr.Zero; pTasks[nFirstSyncTask].mfxBS.DataLength = 0; pTasks[nFirstSyncTask].mfxBS.DataOffset = 0; nFirstSyncTask = (nFirstSyncTask + 1) % taskPoolSize; return(true); } else { for (;;) { // Encode a frame asychronously (returns immediately) //sts = mfxENC.EncodeFrameAsync(NULL, pSurfaces2[nIndex2], &pTasks[nTaskIdx].mfxBS, &pTasks[nTaskIdx].syncp); sts = UnsafeNativeMethods.MFXVideoENCODE_EncodeFrameAsync(session, (mfxEncodeCtrl *)0, null, &pTasks[nTaskIdx].mfxBS, &pTasks[nTaskIdx].syncp); if (mfxStatus.MFX_ERR_NONE < sts && pTasks[nTaskIdx].syncp.sync == IntPtr.Zero) { // repeat the call if warning and no output if (mfxStatus.MFX_WRN_DEVICE_BUSY == sts) { Thread.Sleep(1); // wait if device is busy } } else if (mfxStatus.MFX_ERR_NONE < sts && pTasks[nTaskIdx].syncp.sync != IntPtr.Zero) { sts = mfxStatus.MFX_ERR_NONE; // ignore warnings if output is available break; } else if (mfxStatus.MFX_ERR_NOT_ENOUGH_BUFFER == sts) { // Allocate more bitstream buffer memory here if needed... break; } else { if (sts != mfxStatus.MFX_ERR_MORE_DATA && sts != mfxStatus.MFX_ERR_MORE_SURFACE) { QuickSyncStatic.ThrowOnBadStatus(sts, "encodeAsync"); } break; } } } } if (mfxStatus.MFX_ERR_MORE_DATA == sts) { return(false); } QuickSyncStatic.ThrowOnBadStatus(sts, "enc error"); return(true); }
/// <summary>Get frames during 2nd stage of flushing</summary> /// <param name="bitStreamChunk">A single frame</param> /// <returns>true if you should continue to call this method, false if you must go to the next stage.</returns> public bool Flush2(ref BitStreamChunk bitStreamChunk) { mfxSyncPoint syncpV; mfxFrameSurface1 *pmfxOutSurface = (mfxFrameSurface1 *)0; int nIndex2 = 0; bitStreamChunk.bytesAvailable = 0; //////// mfxStatus sts = mfxStatus.MFX_ERR_NONE; // // Stage 3: Retrieve buffered frames from VPP // if (mfxStatus.MFX_ERR_NONE <= sts || mfxStatus.MFX_ERR_MORE_DATA == sts || mfxStatus.MFX_ERR_MORE_SURFACE == sts) { int nTaskIdx = GetFreeTaskIndex(pTasks, taskPoolSize); // Find free task if ((int)mfxStatus.MFX_ERR_NOT_FOUND == nTaskIdx) { // No more free tasks, need to sync sts = UnsafeNativeMethods.MFXVideoCORE_SyncOperation(session, pTasks[nFirstSyncTask].syncp, 60000); QuickSyncStatic.ThrowOnBadStatus(sts, "syncOper"); if (bitStreamChunk.bitstream == null || bitStreamChunk.bitstream.Length < pTasks[nFirstSyncTask].mfxBS.DataLength) { bitStreamChunk.bitstream = new byte[pTasks[nFirstSyncTask].mfxBS.DataLength]; } Trace.Assert(pTasks[nFirstSyncTask].mfxBS.DataOffset == 0); Marshal.Copy(pTasks[nFirstSyncTask].mfxBS.Data, bitStreamChunk.bitstream, 0, (int)pTasks[nFirstSyncTask].mfxBS.DataLength); bitStreamChunk.bytesAvailable = (int)pTasks[nFirstSyncTask].mfxBS.DataLength; // WriteBitStreamFrame(pTasks[nFirstSyncTask].mfxBS, outbs); //MSDK_BREAK_ON_ERROR(sts); pTasks[nFirstSyncTask].syncp.sync = IntPtr.Zero; pTasks[nFirstSyncTask].mfxBS.DataLength = 0; pTasks[nFirstSyncTask].mfxBS.DataOffset = 0; nFirstSyncTask = (nFirstSyncTask + 1) % taskPoolSize; return(true); } else { int compositeFrameIndex = 0; //morevpp: nIndex2 = GetFreeSurfaceIndex(pSurfaces2, nSurfNumVPPEnc); // Find free frame surface Trace.Assert(nIndex2 != (int)mfxStatus.MFX_ERR_NOT_FOUND); for (;;) { var z = pmfxOutSurface; z = null; // if (compositeFrameIndex == 1) // z = overlay; Trace.Assert(compositeFrameIndex <= 1); // Process a frame asychronously (returns immediately) sts = UnsafeNativeMethods.MFXVideoVPP_RunFrameVPPAsync(session, z, &pSurfaces2[nIndex2], (mfxExtVppAuxData *)0, &syncpV); // COMPOSITING if (mfxStatus.MFX_ERR_NONE < sts && syncpV.sync == IntPtr.Zero) { // repeat the call if warning and no output if (mfxStatus.MFX_WRN_DEVICE_BUSY == sts) { Thread.Sleep(1); // wait if device is busy } } else if (mfxStatus.MFX_ERR_NONE < sts && syncpV.sync != IntPtr.Zero) { sts = mfxStatus.MFX_ERR_NONE; // ignore warnings if output is available break; } else { if (sts != mfxStatus.MFX_ERR_MORE_DATA && sts != mfxStatus.MFX_ERR_MORE_SURFACE) { QuickSyncStatic.ThrowOnBadStatus(sts, "vppAsync"); } break; // not a warning } } //VPP needs more data, let decoder decode another frame as input if (mfxStatus.MFX_ERR_MORE_DATA == sts) { return(false); // compositeFrameIndex++; //goto morevpp; } else if (mfxStatus.MFX_ERR_MORE_SURFACE == sts) { // Not relevant for the illustrated workload! Therefore not handled. // Relevant for cases when VPP produces more frames at output than consumes at input. E.g. framerate conversion 30 fps -> 60 fps QuickSyncStatic.ThrowOnBadStatus(sts, "vpp");; } else if (mfxStatus.MFX_ERR_NONE != sts) { QuickSyncStatic.ThrowOnBadStatus(sts, "vpp"); } ; for (;;) { // Encode a frame asychronously (returns immediately) //sts = mfxENC.EncodeFrameAsync(NULL, pSurfaces2[nIndex2], &pTasks[nTaskIdx].mfxBS, &pTasks[nTaskIdx].syncp); sts = UnsafeNativeMethods.MFXVideoENCODE_EncodeFrameAsync(session, (mfxEncodeCtrl *)0, &pSurfaces2[nIndex2], &pTasks[nTaskIdx].mfxBS, &pTasks[nTaskIdx].syncp); if (mfxStatus.MFX_ERR_NONE < sts && pTasks[nTaskIdx].syncp.sync == IntPtr.Zero) { // repeat the call if warning and no output if (mfxStatus.MFX_WRN_DEVICE_BUSY == sts) { Thread.Sleep(1); // wait if device is busy } } else if (mfxStatus.MFX_ERR_NONE < sts && pTasks[nTaskIdx].syncp.sync != IntPtr.Zero) { sts = mfxStatus.MFX_ERR_NONE; // ignore warnings if output is available break; } else if (mfxStatus.MFX_ERR_NOT_ENOUGH_BUFFER == sts) { // Allocate more bitstream buffer memory here if needed... break; } else { if (sts != mfxStatus.MFX_ERR_MORE_DATA && sts != mfxStatus.MFX_ERR_MORE_SURFACE) { QuickSyncStatic.ThrowOnBadStatus(sts, "encodeAsync"); } break; } } } } // MFX_ERR_MORE_DATA means that file has ended, need to go to buffering loop, exit in case of other errors //MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA); if (sts == mfxStatus.MFX_ERR_MORE_DATA) { return(false); } QuickSyncStatic.ThrowOnBadStatus(sts, "dec or enc or vpp"); return(true); }
/// <summary>Return the next frame available</summary> public IEnumerable <BitStreamChunk> GetFrames() { var inbuf = new byte[lowLevelTranscoder.BufferSize]; BitStreamChunk bsc = new BitStreamChunk(); while (true) { if (lowLevelTranscoder.BufferFreeCount > lowLevelTranscoder.BufferSize / 2) { int r = inStream.Read(inbuf, 0, Math.Min((int)inbuf.Length, lowLevelTranscoder.BufferFreeCount)); if (r <= 0) { break; } lowLevelTranscoder.PutBitstream(inbuf, 0, r); } lowLevelTranscoder.GetNextFrame(ref bsc); if (bsc.bytesAvailable > 0) { yield return(bsc); } } while (lowLevelTranscoder.GetNextFrame(ref bsc)) { if (bsc.bytesAvailable > 0) { yield return(bsc); } } while (lowLevelTranscoder.Flush1(ref bsc)) { if (bsc.bytesAvailable > 0) { yield return(bsc); } } while (lowLevelTranscoder.Flush2(ref bsc)) { if (bsc.bytesAvailable > 0) { yield return(bsc); } } while (lowLevelTranscoder.Flush3(ref bsc)) { if (bsc.bytesAvailable > 0) { yield return(bsc); } } while (lowLevelTranscoder.Flush4(ref bsc)) { if (bsc.bytesAvailable > 0) { yield return(bsc); } } }