/// <summary> /// Initializes a new instance of the <see cref="FFmpegMedia"/> class. /// </summary> /// <param name="filePath">The file path.</param> /// <param name="errorCallback">The error callback.</param> /// <exception cref="System.ArgumentException"> /// errorCallback cannot be null /// or /// filePath cannot be null or empty /// </exception> /// <exception cref="System.Exception"></exception> public FFmpegMedia(string filePath, MediaErrorOccurredCallback errorCallback) { // Argument validation if (errorCallback == null) { throw new ArgumentException("errorCallback cannot be null"); } if (string.IsNullOrWhiteSpace(filePath)) { throw new ArgumentException("filePath cannot be null or empty"); } // Error callback this.ErrorOccurredCallback = errorCallback; // Register the property state change handler this.RealtimeClock.PropertyChanged += (s, e) => { NotifyPlayStateChanged(); }; // Make sure we registwered the library Helper.RegisterFFmpeg(); // Create the audio provider and audio renderer this.PcmAudioProvider = new AudioBufferProvider(this); this.AudioRenderer = new AudioRenderer(); // load input, codec and output contexts this.InitializeMedia(filePath); // Setup the frames Cache this.VideoFramesCache = new FFmpegMediaFrameCache(this.VideoFrameRate, MediaFrameType.Video); this.AudioFramesCache = new FFmpegMediaFrameCache(this.AudioSampleRate / 1000M, MediaFrameType.Audio); // Setup the Leading and Lagging frames cache if (HasVideo && (HasAudio == false || InputAudioStream->index > InputVideoStream->index)) { this.LeadingFramesCache = VideoFramesCache; this.LaggingFramesCache = AudioFramesCache; this.StartDts = InputVideoStream->start_time; LeadingStreamType = MediaFrameType.Video; LaggingStreamType = HasAudio ? MediaFrameType.Audio : MediaFrameType.Unknown; } else { this.LeadingFramesCache = AudioFramesCache; this.LaggingFramesCache = VideoFramesCache; this.StartDts = InputAudioStream->start_time; LeadingStreamType = MediaFrameType.Audio; LaggingStreamType = HasVideo ? MediaFrameType.Video : MediaFrameType.Unknown; } if (Helper.IsNoPtsValue(StartDts)) { StartDts = 0; } // Setup Video Renderer and Video Frames Cache if (HasVideo) { this.VideoRenderer = new WriteableBitmap(this.VideoFrameWidth, this.VideoFrameHeight, 96, 96, System.Windows.Media.PixelFormats.Bgr24, null); } else { this.VideoRenderer = new WriteableBitmap(1, 1, 96, 96, System.Windows.Media.PixelFormats.Bgr24, null); } // Setup Audio Renderer and Audio Frames Cache if (HasAudio) { this.StartAudioRenderer(); } // Start the continuous Decoder thread that fills up our queue. MediaFrameExtractorThread = new Thread(ExtractMediaFramesContinuously) { IsBackground = true, Priority = ThreadPriority.AboveNormal }; // Begin the media extractor MediaFrameExtractorThread.Start(); MediaFramesExtractedDone.Reset(); if (MediaFramesExtractedDone.Wait(Constants.WaitForPlaybackReadyStateTimeout) == false) { throw new Exception(string.Format("Could not load sream frames in a timely manner. Timed out in {0}", Constants.WaitForPlaybackReadyStateTimeout)); } // Initialize the Speed Ratio to 1.0 (Default) this.SpeedRatio = Constants.DefaultSpeedRatio; // Start the render timer on the UI thread. this.VideoRenderTimer.Tick += RenderVideoImage; this.VideoRenderTimer.Interval = TimeSpan.FromMilliseconds(Constants.VideoRenderTimerIntervalMillis); this.VideoRenderTimer.IsEnabled = true; this.VideoRenderTimer.Start(); }
/// <summary> /// Initializes a new instance of the <see cref="FFmpegMedia" /> class. /// </summary> /// <param name="filePath">The file path.</param> /// <param name="errorCallback">The error callback.</param> /// <param name="referer">The referer. Leave null or emtpy to skip setting it.</param> /// <param name="userAgent">The user agent. Leave null or empty in order to skip setting a User Agent</param> /// <exception cref="ArgumentException">errorCallback cannot be null /// or /// filePath cannot be null or empty</exception> /// <exception cref="Exception"></exception> /// <exception cref="System.ArgumentException">errorCallback cannot be null /// or /// filePath cannot be null or empty</exception> /// <exception cref="System.Exception"></exception> public FFmpegMedia(string filePath, MediaErrorOccurredCallback errorCallback, string referer, string userAgent) { // Argument validation if (errorCallback == null) throw new ArgumentException("errorCallback cannot be null"); if (string.IsNullOrWhiteSpace(filePath)) throw new ArgumentException("filePath cannot be null or empty"); // Error callback this.ErrorOccurredCallback = errorCallback; // Register the property state change handler this.RealtimeClock.PropertyChanged += (s, e) => { NotifyPlayStateChanged(); }; // Make sure we registwered the library Helper.RegisterFFmpeg(); // Create the audio provider and audio renderer this.PcmAudioProvider = new AudioBufferProvider(this); this.AudioRenderer = new AudioRenderer(); // load input, codec and output contexts this.InitializeMedia(filePath, null, referer, userAgent); // Setup the frames Cache this.VideoFramesCache = new FFmpegMediaFrameCache(this.VideoFrameRate * (int)FramesCacheLength.TotalSeconds, MediaFrameType.Video); this.AudioFramesCache = new FFmpegMediaFrameCache(this.AudioSampleRate / (int)FramesCacheLength.TotalMilliseconds, MediaFrameType.Audio); // Setup the Leading and Lagging frames cache if (HasVideo && (HasAudio == false || InputAudioStream->index > InputVideoStream->index)) { this.PrimaryFramesCache = VideoFramesCache; this.SecondaryFramesCache = AudioFramesCache; this.StartDts = InputVideoStream->start_time; LeadingStreamType = MediaFrameType.Video; LaggingStreamType = HasAudio ? MediaFrameType.Audio : MediaFrameType.Unknown; } else { this.PrimaryFramesCache = AudioFramesCache; this.SecondaryFramesCache = VideoFramesCache; this.StartDts = InputAudioStream->start_time; LeadingStreamType = MediaFrameType.Audio; LaggingStreamType = HasVideo ? MediaFrameType.Video : MediaFrameType.Unknown; } if (Helper.IsNoPtsValue(StartDts)) StartDts = 0; // Setup Video Renderer and Video Frames Cache if (HasVideo) this.VideoRenderer = new WriteableBitmap(this.VideoFrameWidth, this.VideoFrameHeight, 96, 96, System.Windows.Media.PixelFormats.Bgr24, null); else this.VideoRenderer = new WriteableBitmap(1, 1, 96, 96, System.Windows.Media.PixelFormats.Bgr24, null); // Setup Audio Renderer and Audio Frames Cache if (HasAudio) { this.StartAudioRenderer(); } // Start the continuous Decoder thread that fills up our queue. MediaFrameExtractorThread = new Thread(ExtractMediaFramesContinuously) { IsBackground = true, Priority = ThreadPriority.AboveNormal }; // Begin the media extractor MediaFrameExtractorThread.Start(); MediaFramesExtractedDone.Reset(); if (MediaFramesExtractedDone.Wait(Constants.WaitForPlaybackReadyStateTimeout) == false) { throw new Exception(string.Format("Could not load sream frames in a timely manner. Timed out in {0}", Constants.WaitForPlaybackReadyStateTimeout)); } // Initialize the Speed Ratio to 1.0 (Default) this.SpeedRatio = Constants.DefaultSpeedRatio; // Start the render timer on the UI thread. this.VideoRenderTimer.Tick += RenderVideoImage; this.VideoRenderTimer.Interval = TimeSpan.FromMilliseconds(Constants.VideoRenderTimerIntervalMillis); this.VideoRenderTimer.IsEnabled = true; this.VideoRenderTimer.Start(); }