Пример #1
0
        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Close the Media sink
        /// </summary>
        /// <param name="writerObject">the media source object</param>
        /// <history>
        ///    01 Nov 18  Cynic - Started
        /// </history>
        private void CloseSinkWriter(IMFSinkWriter writerObject)
        {
            // End any active captures
            if (writerObject == null)
            {
                LogMessage("CloseSinkWriter rwriterObject == null");
                return;
            }

            // close and release
            HResult hr = writerObject.Finalize_();

            Marshal.ReleaseComObject(writerObject);
        }
Пример #2
0
        public int StopCapture()
        {
            var hr = S_Ok;

            lock (LockSync)
            {
                if (PWriter != null)
                {
                    hr = PWriter.Finalize_();
                    SafeRelease(PWriter);
                    PWriter = null;
                }
            }

            return(hr);
        }
Пример #3
0
        //-------------------------------------------------------------------
        //  CloseDevice
        //
        //  Releases all resources held by this object.
        //-------------------------------------------------------------------

        public HResult CloseDevice()
        {
            lock (this)
            {
                if (m_pWriter != null)
                {
                    m_pWriter.Finalize_();
                    SafeRelease(m_pWriter);
                    m_pWriter = null;
                }

                SafeRelease(m_pReader);
                m_pReader = null;

                m_pwszSymbolicLink = null;
            }

            return(HResult.S_OK);
        }
Пример #4
0
 /// <summary>
 ///  stops the process of recording. finalizes and then releases the sink writer
 /// </summary>
 /// <returns>z success, nz fail</returns>
 public int StopRecording()
 {
     LogMessage("StopRecording called");
     // End any active captures
     if (workingSinkWriter != null)
     {
         lock (sinkWriterLockObject)
         {
             // close and release
             workingSinkWriter.Finalize_();
             Marshal.ReleaseComObject(workingSinkWriter);
             workingSinkWriter = null;
         }
     }
     // reset these
     sinkWriterVideoStreamId = -1;
     isFirstSample           = true;
     firstSampleBaseTime     = 0;
     wantTimebaseRebase      = false;
     return(0);
 }
Пример #5
0
        public HResult EndCaptureSession()
        {
            HResult hr = HResult.S_OK;

            lock (this)
            {
                if (m_pWriter != null)
                {
                    hr = m_pWriter.Finalize_();
                    SafeRelease(m_pWriter);
                    m_pWriter = null;
                }

                if (m_pReader != null)
                {
                    SafeRelease(m_pReader);
                    m_pReader = null;
                }
            }

            return(hr);
        }
Пример #6
0
        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Does everything to copy a file. Opens the Source Reader and Sink Writer
        /// configures the streams and then, because a Synchronous version
        /// of the Source Reader is used, we sit in a loop and perform the copy.
        ///
        /// Any errors here simply throw an exception and must be trapped elsewhere
        ///
        /// Note that because this code is intended for demo purposes, it has been
        /// kept very simple and linear. Most of the things that could have been
        /// refactored in a common procedure (audio and video streams) are simply
        /// written out in duplicate in order to make it obvious what is going on.
        /// </summary>
        /// <param name="sourceFileName">the source file name</param>
        /// <param name="outputFileName">the name of the output file</param>
        /// <history>
        ///    01 Nov 18  Cynic - Originally Written
        /// </history>
        public void CopyFile(string sourceFileName, string outputFileName)
        {
            HResult hr;
            int     sinkWriterOutputVideoStreamId = -1;
            int     videoSamplesProcessed         = 0;
            bool    videoStreamIsAtEOS            = false;
            int     sourceReaderVideoStreamId     = -1;

            int  sinkWriterOutputAudioStreamId = -1;
            int  audioSamplesProcessed         = 0;
            bool audioStreamIsAtEOS            = false;
            int  sourceReaderAudioStreamId     = -1;

            // not keen on endless loops. This is the maximum number
            // of streams we will check in the source reader.
            const int MAX_SOURCEREADER_STREAMS = 100;

            // create the SourceReader
            sourceReader = TantaWMFUtils.CreateSourceReaderSyncFromFile(sourceFileName, DEFAULT_ALLOW_HARDWARE_TRANSFORMS);
            if (sourceReader == null)
            {
                // we failed
                throw new Exception("CopyFile: Failed to create SourceReader, Nothing will work.");
            }
            // create the SinkWriter
            sinkWriter = TantaWMFUtils.CreateSinkWriterFromFile(outputFileName, DEFAULT_ALLOW_HARDWARE_TRANSFORMS);
            if (sinkWriter == null)
            {
                // we failed
                throw new Exception("CopyFile: Failed to create Sink Writer, Nothing will work.");
            }

            // find the first audio and video stream and identify the default Media Type
            // they are using. We could look into the streams and enumerate all of the
            // types on offer and choose one from the list - but for a copy operation
            // the default will be quite suitable.

            sourceReaderNativeVideoMediaType = null;
            sourceReaderNativeAudioMediaType = null;
            for (int streamIndex = 0; streamIndex < MAX_SOURCEREADER_STREAMS; streamIndex++)
            {
                IMFMediaType workingType   = null;
                Guid         guidMajorType = Guid.Empty;

                // if we have found both the video and audio types (and their stream ids) leave now
                if ((sourceReaderNativeVideoMediaType != null) && (sourceReaderNativeAudioMediaType != null))
                {
                    break;
                }

                hr = sourceReader.GetNativeMediaType(streamIndex, 0, out workingType);
                if (hr == HResult.MF_E_NO_MORE_TYPES)
                {
                    break;
                }
                if (hr == HResult.MF_E_INVALIDSTREAMNUMBER)
                {
                    break;
                }
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("CopyFile: failed on call to GetNativeMediaType, retVal=" + hr.ToString());
                }
                if (workingType == null)
                {
                    // we failed
                    throw new Exception("CopyFile: failed on call to GetNativeMediaType, workingType == null");
                }

                // what major type does this stream have?
                hr = workingType.GetMajorType(out guidMajorType);
                if (hr != HResult.S_OK)
                {
                    throw new Exception("CopyFile:  call to workingType.GetMajorType failed. Err=" + hr.ToString());
                }
                if (guidMajorType == null)
                {
                    throw new Exception("CopyFile:  call to workingType.GetMajorType failed. guidMajorType == null");
                }

                // test for video or audio (there can be others)
                if ((guidMajorType == MFMediaType.Video) && (sourceReaderNativeVideoMediaType == null))
                {
                    // this stream represents a video type
                    sourceReaderNativeVideoMediaType = workingType;
                    sourceReaderVideoStreamId        = streamIndex;
                    // the sourceReaderNativeVideoMediaType will be released elsewhere
                    continue;
                }
                else if ((guidMajorType == MFMediaType.Audio) && (sourceReaderNativeAudioMediaType == null))
                {
                    // this stream represents a audio type
                    sourceReaderNativeAudioMediaType = workingType;
                    sourceReaderAudioStreamId        = streamIndex;
                    // the sourceReaderNativeAudioMediaType will be released elsewhere
                    continue;
                }

                // if we get here release the type - we do not use it
                if (workingType != null)
                {
                    Marshal.ReleaseComObject(workingType);
                    workingType = null;
                }
            }

            // at this point we expect we can have a native video or a native audio media type
            // or both, but not neither. if we don't we cannot carry on
            if ((sourceReaderNativeVideoMediaType == null) && (sourceReaderNativeAudioMediaType == null))
            {
                // we failed
                throw new Exception("CopyFile: failed on call to GetNativeMediaType, sourceReaderNativeVideoMediaType == null");
            }

            // if we have a video stream in the source file we now set it up
            if (sourceReaderNativeVideoMediaType != null)
            {
                // set the media type on the reader - this is the media type it will output
                hr = sourceReader.SetCurrentMediaType(sourceReaderVideoStreamId, null, sourceReaderNativeVideoMediaType);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("CopyFile: failed on call to SetCurrentMediaType(v), retVal=" + hr.ToString());
                }
                // add a stream to the sink writer. The mediaType specifies the format of the samples that will be written
                // to the file. Note that it does not necessarily need to match the input format. To set the input format
                // use SetInputMediaType. In this case it does match because we copied the video encoder information directly
                // out of the video source type
                hr = sinkWriter.AddStream(sourceReaderNativeVideoMediaType, out sinkWriterOutputVideoStreamId);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("CopyFile: Failed adding the output stream(v), retVal=" + hr.ToString());
                }
                // Set the input format for a stream on the sink writer. Note the use of the stream index here
                // The input format does not have to match the target format that is written to the media sink
                // If the formats do not match, this call attempts to load an transform
                // that can convert from the input format to the target format. If it cannot find one, and this is not
                // a sure thing, it will throw an exception.
                hr = sinkWriter.SetInputMediaType(sinkWriterOutputVideoStreamId, sourceReaderNativeVideoMediaType, null);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("CopyFile: Failed on calling SetInputMediaType(v) on the writer, retVal=" + hr.ToString());
                }
            }

            // if we have an audio stream in the source file we now set it up
            if (sourceReaderNativeAudioMediaType != null)
            {
                // set the media type on the reader - this is the media type it will output
                hr = sourceReader.SetCurrentMediaType(sourceReaderAudioStreamId, null, sourceReaderNativeAudioMediaType);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("CopyFile: failed on call to SetCurrentMediaType(a), retVal=" + hr.ToString());
                }
                // add a stream to the sink writer. The mediaType specifies the format of the samples that will be written
                // to the file. Note that it does not necessarily need to match the input format. To set the input format
                // use SetInputMediaType. In this case it does match because we copied the video encoder information directly
                // out of the video source type
                hr = sinkWriter.AddStream(sourceReaderNativeAudioMediaType, out sinkWriterOutputAudioStreamId);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("CopyFile: Failed adding the output stream(a), retVal=" + hr.ToString());
                }
                // Set the input format for a stream on the sink writer. Note the use of the stream index here
                // The input format does not have to match the target format that is written to the media sink
                // If the formats do not match, this call attempts to load an transform
                // that can convert from the input format to the target format. If it cannot find one, and this is not
                // a sure thing, it will throw an exception.
                hr = sinkWriter.SetInputMediaType(sinkWriterOutputAudioStreamId, sourceReaderNativeAudioMediaType, null);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("CopyFile: Failed on calling SetInputMediaType(a) on the writer, retVal=" + hr.ToString());
                }
            }

            // begin writing on the sink writer
            hr = sinkWriter.BeginWriting();
            if (hr != HResult.S_OK)
            {
                // we failed
                throw new Exception("CopyFile: failed on call to BeginWriting, retVal=" + hr.ToString());
            }

            // we sit in a loop here and get the sample from the source reader and write it out
            // to the sink writer. An EOS (end of sample) value in the flags will signal the end.
            while (true)
            {
                int actualStreamIndex;
                MF_SOURCE_READER_FLAG actualStreamFlags;
                long      timeStamp          = 0;
                IMFSample workingMediaSample = null;

                // Request the next sample from the media source. Note that this could be
                // any type of media sample (video, audio, subtitles etc). We do not know
                // until we look at the stream ID. We saved the stream ID earlier when
                // we obtained the media types and so we can branch based on that.
                hr = sourceReader.ReadSample(
                    TantaWMFUtils.MF_SOURCE_READER_ANY_STREAM,
                    0,
                    out actualStreamIndex,
                    out actualStreamFlags,
                    out timeStamp,
                    out workingMediaSample
                    );
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("CopyFile: Failed on calling the ReadSample on the reader, retVal=" + hr.ToString());
                }

                // the sample may be null if either end of stream or a stream tick is returned
                if (workingMediaSample == null)
                {
                    // just ignore, the flags will have the information we need.
                }
                else
                {
                    // the sample is not null
                    if (actualStreamIndex == sourceReaderAudioStreamId)
                    {
                        // audio data
                        // ensure discontinuity is set for the first sample in each stream
                        if (audioSamplesProcessed == 0)
                        {
                            // audio data
                            hr = workingMediaSample.SetUINT32(MFAttributesClsid.MFSampleExtension_Discontinuity, 1);
                            if (hr != HResult.S_OK)
                            {
                                // we failed
                                throw new Exception("CopyFile: Failed on calling SetUINT32 on the sample, retVal=" + hr.ToString());
                            }
                            // remember this - we only do it once
                            audioSamplesProcessed++;
                        }
                        hr = sinkWriter.WriteSample(sinkWriterOutputAudioStreamId, workingMediaSample);
                        if (hr != HResult.S_OK)
                        {
                            // we failed
                            throw new Exception("CopyFile: Failed on calling the WriteSample on the writer, retVal=" + hr.ToString());
                        }
                    }
                    else if (actualStreamIndex == sourceReaderVideoStreamId)
                    {
                        // video data
                        // ensure discontinuity is set for the first sample in each stream
                        if (videoSamplesProcessed == 0)
                        {
                            // video data
                            hr = workingMediaSample.SetUINT32(MFAttributesClsid.MFSampleExtension_Discontinuity, 1);
                            if (hr != HResult.S_OK)
                            {
                                // we failed
                                throw new Exception("CopyFile: Failed on calling SetUINT32 on the sample, retVal=" + hr.ToString());
                            }
                            // remember this - we only do it once
                            videoSamplesProcessed++;
                        }
                        hr = sinkWriter.WriteSample(sinkWriterOutputVideoStreamId, workingMediaSample);
                        if (hr != HResult.S_OK)
                        {
                            // we failed
                            throw new Exception("CopyFile: Failed on calling the WriteSample on the writer, retVal=" + hr.ToString());
                        }
                    }

                    // release the sample
                    if (workingMediaSample != null)
                    {
                        Marshal.ReleaseComObject(workingMediaSample);
                        workingMediaSample = null;
                    }
                }

                // do we have a stream tick event?
                if ((actualStreamFlags & MF_SOURCE_READER_FLAG.StreamTick) != 0)
                {
                    if (actualStreamIndex == sourceReaderVideoStreamId)
                    {
                        // video stream
                        hr = sinkWriter.SendStreamTick(sinkWriterOutputVideoStreamId, timeStamp);
                    }
                    else if (actualStreamIndex == sourceReaderAudioStreamId)
                    {
                        // audio stream
                        hr = sinkWriter.SendStreamTick(sinkWriterOutputAudioStreamId, timeStamp);
                    }
                    else
                    {
                    }
                }

                // is this stream at an END of Segment
                if ((actualStreamFlags & MF_SOURCE_READER_FLAG.EndOfStream) != 0)
                {
                    // We have an EOS - but is it on the video or audio channel?
                    // we have to get it on both
                    if (actualStreamIndex == sourceReaderVideoStreamId)
                    {
                        // video stream
                        // have we seen this before?
                        if (videoStreamIsAtEOS == false)
                        {
                            hr = sinkWriter.NotifyEndOfSegment(sinkWriterOutputVideoStreamId);
                            if (hr != HResult.S_OK)
                            {
                                // we failed
                                throw new Exception("CopyFile: Failed on calling the NotifyEndOfSegment on video stream, retVal=" + hr.ToString());
                            }
                            videoStreamIsAtEOS = true;
                        }
                    }
                    else if (actualStreamIndex == sourceReaderAudioStreamId)
                    {
                        // audio stream
                        // have we seen this before?
                        if (audioStreamIsAtEOS == false)
                        {
                            hr = sinkWriter.NotifyEndOfSegment(sinkWriterOutputAudioStreamId);
                            if (hr != HResult.S_OK)
                            {
                                // we failed
                                throw new Exception("CopyFile: Failed on calling the NotifyEndOfSegment on audio stream, retVal=" + hr.ToString());
                            }
                            audioStreamIsAtEOS = true;
                        }
                        // audio stream
                    }
                    else
                    {
                    }

                    // our exit condition depends on which streams are in use
                    if ((sourceReaderNativeVideoMediaType != null) && (sourceReaderNativeAudioMediaType != null))
                    {
                        // if both streams are at EOS we can leave
                        if ((videoStreamIsAtEOS == true) && (audioStreamIsAtEOS == true))
                        {
                            break;
                        }
                    }
                    else if (sourceReaderNativeVideoMediaType != null)
                    {
                        // only video is active, if the video stream is EOS we can leave
                        if (videoStreamIsAtEOS == true)
                        {
                            break;
                        }
                    }
                    else if (sourceReaderNativeAudioMediaType != null)
                    {
                        // only audio is active, if the audio stream is EOS we can leave
                        if (audioStreamIsAtEOS == true)
                        {
                            break;
                        }
                    }
                }
            } // bottom of endless for loop

            hr = sinkWriter.Finalize_();
            if (hr != HResult.S_OK)
            {
                // we failed
                throw new Exception("Failed on call tosinkWriter.Finalize(), retVal=" + hr.ToString());
            }
        }