/// <summary>
        ///     Use Source Reader to allocate a sample
        /// </summary>
        /// <param name="sourceReader">The Source Reader</param>
        /// <param name="dwStreamIndex">The stream to pull data from</param>
        /// <param name="dwControlFlags">A bitwise OR of zero or more flags from the MF_SOURCE_READER_CONTROL_FLAG enumeration</param>
        /// <param name="pdwActualStreamIndex">Receives the zero-based index of the stream</param>
        /// <param name="pdwStreamFlags">Receives a bitwise OR of zero or more flags from the MF_SOURCE_READER_FLAG enumeration</param>
        /// <param name="pllTimestamp">Receives the time stamp of the sample, or the time of the stream event indicated in pdwStreamFlags. The time is given in 100-nanosecond units</param>
        /// <returns>An encapsulated sample</returns>
        public static EncapsulatedSample ReadSample(
            IMFSourceReader sourceReader,
            uint dwStreamIndex,
            uint dwControlFlags,
            out uint pdwActualStreamIndex,
            out uint pdwStreamFlags,
            out ulong pllTimestamp)
        {
            EncapsulatedSample sample = new EncapsulatedSample();

            sample.ReadSampleFrom(
                sourceReader,
                dwStreamIndex,
                dwControlFlags,
                out pdwActualStreamIndex,
                out pdwStreamFlags,
                out pllTimestamp);

            return(sample);
        }
        private bool ProcessSamples()
        {
            IMFMediaType       mediaType = null;
            EncapsulatedSample sample    = null;

            uint  actualStreamIndex = 0;
            uint  flags             = 0;
            uint  endOfStream       = 0;
            ulong timestamp         = 0;
            ulong sampleDuration    = 0;

            // Set the start position
            object varPosition = (long)this.startTime;

            this.sourceReader.SetCurrentPosition(Guid.Empty, ref varPosition);
            this.sourceReader.Flush(Consts.MF_SOURCE_READER_ALL_STREAMS);

            // SourceReader's SetCurrentPosition don't guarantee the decoder will seek to
            // the exact requested position, so more samples are requested until the desired
            // position is reached
            do
            {
                // Dispose the unmanaged memory if needed
                if (sample != null)
                {
                    sample.Dispose();
                }

                sample = EncapsulatedSample.ReadSample(
                    this.sourceReader,
                    Consts.MF_SOURCE_READER_ANY_STREAM,
                    0,
                    out actualStreamIndex,
                    out flags,
                    out timestamp);

                // Throw an exception if the source reader reported an error
                if ((flags & (uint)Enums.MF_SOURCE_READER_FLAG.ERROR) != 0)
                {
                    throw new ApplicationException("IMFSourceReader::ReadSample reported an error (MF_SOURCE_READERF_ERROR)");
                }

                // Get the sample duration
                if (sample.MfSample != null)
                {
                    sample.MfSample.GetSampleDuration(out sampleDuration);
                }
                else
                {
                    sampleDuration = 0;
                }
            }while (timestamp + sampleDuration < this.startTime);

            // Prepare for writing
            this.sinkWriter.BeginWriting();

            int progress = 0;

            this.lastProgressUpdate = DateTime.Now.Ticks;

            // Continue the operation until all streams are at the EOS
            while (endOfStream < this.selectedStreams)
            {
                // Cancel the operation if requested by the Background Worker
                if (this.encodeWorker.CancellationPending)
                {
                    return(false);
                }

                // Read a new sample
                if (sample == null)
                {
                    sample = EncapsulatedSample.ReadSample(
                        this.sourceReader,
                        Consts.MF_SOURCE_READER_ANY_STREAM,
                        0,
                        out actualStreamIndex,
                        out flags,
                        out timestamp);
                }

                // Throw an exception if the source reader reported an error
                if ((flags & (uint)Enums.MF_SOURCE_READER_FLAG.ERROR) != 0)
                {
                    throw new ApplicationException("IMFSourceReader::ReadSample reported an error (MF_SOURCE_READERF_ERROR)");
                }

                // Report the progress if the interval is reached
                if (TimeSpan.FromTicks(DateTime.Now.Ticks - lastProgressUpdate).TotalMilliseconds > UPDATE_PROGRESS_INTERVAL_MS)
                {
                    // The BackgroundWorker reports the progress using an integer, but we are using a double in WPF (from 0.0 to 100.0) so
                    // to have a smooth transition this class will calculate the progress from 0 to 1000000000 and divide it by 10000000
                    // before reporting it back
                    progress = (int)(((double)(timestamp - this.startTime) / (double)(this.endTime - this.startTime)) * 1000000000);
                    this.encodeWorker.ReportProgress(((progress > 1000000000) ? 1000000000 : progress));
                    lastProgressUpdate = DateTime.Now.Ticks;
                }

                // If the media type changed propagate it to the Sink Writer
                if ((flags & (uint)Enums.MF_SOURCE_READER_FLAG.CURRENTMEDIATYPECHANGED) != 0)
                {
                    this.sourceReader.GetCurrentMediaType(actualStreamIndex, out mediaType);
                    this.sinkWriter.SetInputMediaType(this.streamsInfo[actualStreamIndex].OutputStreamIndex, mediaType, null);
                }

                // Propagate streams tick
                if ((flags & (uint)Enums.MF_SOURCE_READER_FLAG.STREAMTICK) != 0)
                {
                    this.sinkWriter.SendStreamTick(this.streamsInfo[actualStreamIndex].OutputStreamIndex, timestamp - this.startTime);
                }

                if (sample.MfSample != null)
                {
                    // Fix the sample's timestamp
                    sample.MfSample.SetSampleTime(timestamp - this.startTime);

                    // Write the sample
                    this.sinkWriter.WriteSample(this.streamsInfo[actualStreamIndex].OutputStreamIndex, sample.MfSample);
                }

                // If this was the last sample from the stream or we reached the ending position
                if ((flags & (uint)Enums.MF_SOURCE_READER_FLAG.ENDOFSTREAM) != 0 || (this.endTime <= timestamp))
                {
                    // Send an end of segment to Sink Writer
                    this.sinkWriter.NotifyEndOfSegment(this.streamsInfo[actualStreamIndex].OutputStreamIndex);

                    // Disable the stream
                    this.sourceReader.SetStreamSelection(actualStreamIndex, false);

                    // One less stream left
                    endOfStream++;
                }

                // If this was the last stream then finalize the operation
                if (endOfStream == this.selectedStreams)
                {
                    this.encodeWorker.ReportProgress(1000000000);
                    this.sinkWriter.DoFinalize();
                }

                // Dispose the sample
                sample.Dispose();
                sample = null;
            }

            return(true);
        }