/// <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); }