예제 #1
0
        protected int ProcessOutput()
        {
            Debug.Assert(m_bSampleNotify || m_bRepaint);  // See note above.

            int hr = S_Ok;
            ProcessOutputStatus dwStatus = 0;
            long mixerStartTime = 0, mixerEndTime = 0;
            long systemTime = 0;
            bool bRepaint = m_bRepaint; // Temporarily store this state flag.

            MFTOutputDataBuffer[] dataBuffer = new MFTOutputDataBuffer[1];

            IMFSample pSample = null;

            // If the clock is not running, we present the first sample,
            // and then don't present any more until the clock starts.

            if ((m_RenderState != RenderState.Started) &&  // Not running.
                 !m_bRepaint &&                             // Not a repaint request.
                 m_bPrerolled                               // At least one sample has been presented.
                 )
            {
                return S_False;
            }

            // Make sure we have a pointer to the mixer.
            if (m_pMixer == null)
            {
                return MFError.MF_E_INVALIDREQUEST;
            }

            if (!m_bRepaint)
            {
                MFTOutputStatusFlags osf;
                hr = m_pMixer.GetOutputStatus(out osf);
                MFError.ThrowExceptionForHR(hr);

                if ((osf & MFTOutputStatusFlags.SampleReady) == 0)
                {
                    m_bSampleNotify = false;
                    return S_Ok;
                }
            }

            try
            {
                // Try to get a free sample from the video sample pool.
                m_SamplePool.GetSample(out pSample);

                if (pSample == null)
                {
                    return S_False; // No free samples. We'll try again when a sample is released.
                }

                // (If the following assertion fires, it means we are not managing the sample pool correctly.)
                //Debug.Assert(MFGetAttributeUINT32(pSample, MFSamplePresenter_SampleCounter, -1) == m_TokenCounter);

                if (m_bRepaint)
                {
                    // Repaint request. Ask the mixer for the most recent sample.
                    SetDesiredSampleTime(pSample, m_scheduler.LastSampleTime(), m_scheduler.FrameDuration());
                    m_bRepaint = false; // OK to clear this flag now.
                }
                else
                {
                    // Not a repaint request. Clear the desired sample time; the mixer will
                    // give us the next frame in the stream.
                    ClearDesiredSampleTime(pSample);

                    if (m_pClock != null)
                    {
                        // Latency: Record the starting time for the ProcessOutput operation.
                        hr = m_pClock.GetCorrelatedTime(0, out mixerStartTime, out systemTime);
                        MFError.ThrowExceptionForHR(hr);
                    }
                }

                // Now we are ready to get an output sample from the mixer.
                dataBuffer[0].dwStreamID = 0;
                dataBuffer[0].dwStatus = 0;
                dataBuffer[0].pEvents = null;
                dataBuffer[0].pSample = Marshal.GetIUnknownForObject(pSample);

                try
                {
                    hr = m_pMixer.ProcessOutput(0, 1, dataBuffer, out dwStatus);
                    MFError.ThrowExceptionForHR(hr);

                    // Release any events that were returned from the ProcessOutput method.
                    // (We don't expect any events from the mixer, but this is a good practice.)
                    ReleaseEventCollection(dataBuffer.Length, dataBuffer);
                }
                catch (Exception e)
                {
                    hr = Marshal.GetHRForException(e);
                }
                finally
                {
                    Marshal.Release(dataBuffer[0].pSample);
                    //SafeRelease(dataBuffer[0].pSample);
                }

                if (Failed(hr))
                {
                    // Return the sample to the pool.
                    m_SamplePool.ReturnSample(pSample);

                    // Handle some known error codes from ProcessOutput.
                    if (hr == MFError.MF_E_TRANSFORM_TYPE_NOT_SET)
                    {
                        // The mixer's format is not set. Negotiate a new format.
                        RenegotiateMediaType();
                    }
                    else if (hr == MFError.MF_E_TRANSFORM_STREAM_CHANGE)
                    {
                        // There was a dynamic media type change. Clear our media type.
                        SetMediaType(null);
                    }
                    else if (hr == MFError.MF_E_TRANSFORM_NEED_MORE_INPUT)
                    {
                        // The mixer needs more input.
                        // We have to wait for the mixer to get more input.
                        m_bSampleNotify = false;
                    }
                    else
                    {
                        MFError.ThrowExceptionForHR(hr);
                    }
                }
                else
                {
                    // We got an output sample from the mixer.

                    if (m_pClock != null && !bRepaint)
                    {
                        // Latency: Record the ending time for the ProcessOutput operation,
                        // and notify the EVR of the latency.

                        hr = m_pClock.GetCorrelatedTime(0, out mixerEndTime, out systemTime);
                        MFError.ThrowExceptionForHR(hr);
                        long latencyTime = mixerEndTime - mixerStartTime;

                        GCHandle gh = GCHandle.Alloc(latencyTime, GCHandleType.Pinned);

                        try
                        {
                            // This event (EventCode.ProcessingLatency) isn't defined until DirectShowNet v2.1
                            NotifyEvent((EventCode)0x21, gh.AddrOfPinnedObject(), IntPtr.Zero);
                        }
                        finally
                        {
                            gh.Free();
                        }
                    }

                    // Set up notification for when the sample is released.
                    TrackSample(pSample);

                    // Schedule the sample.
                    if ((m_FrameStep.state == FrameStepRate.None) || bRepaint)
                    {
                        DeliverSample(pSample, bRepaint);
                    }
                    else
                    {
                        // We are frame-stepping (and this is not a repaint request).
                        DeliverFrameStepSample(pSample);
                    }
                    m_bPrerolled = true; // We have presented at least one sample now.
                }
            }
            finally
            {
                //SafeRelease(pSample);
            }

            return S_Ok;
        }
예제 #2
0
 protected void ReleaseEventCollection(int cOutputBuffers, MFTOutputDataBuffer[] pBuffers)
 {
     for (int i = 0; i < cOutputBuffers; i++)
     {
         SafeRelease(pBuffers[i].pEvents);
         pBuffers[i].pEvents = null;
     }
 }
예제 #3
0
 /// <summary>
 /// The routine that usually performs the transform.
 /// </summary>
 /// <param name="pOutputSamples">The structure to populate with output values.</param>
 /// <returns>S_Ok unless error.</returns>
 /// <remarks>
 /// The input sample is in InputSample.  Process it into the pOutputSamples struct.
 /// Depending on what you set in On*StreamInfo, you can either perform
 /// in-place processing by modifying the input sample (which still must
 /// set inout the struct), or create a new IMFSample and FULLY populate
 /// it from the input.  If the input sample has been fully processed,
 /// set InputSample to null.
 /// </remarks>
 abstract protected HResult OnProcessOutput(ref MFTOutputDataBuffer pOutputSamples);