/// <summary> /// Creates a frame source object given the raw FFmpeg frame reference. /// </summary> /// <param name="frame">The raw FFmpeg frame pointer.</param> /// <returns>Create a managed fraome from an unmanaged one.</returns> protected override unsafe MediaFrame CreateFrameSource(ref AVFrame *frame) { if (string.IsNullOrWhiteSpace(FilterString) == false) { InitializeFilterGraph(frame); } if (HardwareAccelerator != null) { frame = HardwareAccelerator.ExchangeFrame(CodecContext, frame, out IsUsingHardwareDecoding); } AVFrame *outputFrame; // TODO: Support real-time changes in Video Filtergraph by checking if MediaOptions.VideoFilterGraph has changed // Maybe expose the VideoFilterGraph string as a MediaElement Control Property if (FilterGraph != null) { // Allocate the output frame outputFrame = ffmpeg.av_frame_clone(frame); var result = ffmpeg.av_buffersrc_add_frame(SourceFilter, outputFrame); while (result >= 0) { result = ffmpeg.av_buffersink_get_frame_flags(SinkFilter, outputFrame, 0); } if (outputFrame->width <= 0 || outputFrame->height <= 0) { // If we don't have a valid output frame simply release it and // return the original input frame RC.Current.Remove(outputFrame); ffmpeg.av_frame_free(&outputFrame); outputFrame = frame; } else { // the output frame is the new valid frame (output frame). // threfore, we need to release the original RC.Current.Remove(frame); var framePtr = frame; ffmpeg.av_frame_free(&framePtr); } } else { outputFrame = frame; } // Check if the output frame is valid if (outputFrame->width <= 0 || outputFrame->height <= 0) { return(null); } // Create the frame holder object and return it. var frameHolder = new VideoFrame(outputFrame, this); CurrentFrameRate = ffmpeg.av_guess_frame_rate(Container.InputContext, Stream, outputFrame).ToDouble(); return(frameHolder); }
/// <inheritdoc /> protected override MediaFrame CreateFrameSource(IntPtr framePointer) { // Validate the video frame var frame = (AVFrame *)framePointer; if (framePointer == IntPtr.Zero || frame->width <= 0 || frame->height <= 0) { return(null); } // Move the frame from hardware (GPU) memory to RAM (CPU) if (HardwareAccelerator != null) { frame = HardwareAccelerator.ExchangeFrame(CodecContext, frame, out var isHardwareFrame); IsUsingHardwareDecoding = isHardwareFrame; } // Init the filter graph for the frame if (string.IsNullOrWhiteSpace(FilterString) == false) { InitializeFilterGraph(frame); } AVFrame *outputFrame; // Changes in the filter graph can be applied by calling the ChangeMedia command if (FilterGraph != null) { // Allocate the output frame outputFrame = MediaFrame.CloneAVFrame(frame); var result = ffmpeg.av_buffersrc_add_frame(SourceFilter, outputFrame); while (result >= 0) { result = ffmpeg.av_buffersink_get_frame_flags(SinkFilter, outputFrame, 0); } if (outputFrame->width <= 0 || outputFrame->height <= 0) { // If we don't have a valid output frame simply release it and // return the original input frame MediaFrame.ReleaseAVFrame(outputFrame); outputFrame = frame; } else { // the output frame is the new valid frame (output frame). // therefore, we need to release the original MediaFrame.ReleaseAVFrame(frame); } } else { outputFrame = frame; } // Check if the output frame is valid if (outputFrame->width <= 0 || outputFrame->height <= 0) { return(null); } // Create the frame holder object and return it. return(new VideoFrame(outputFrame, this)); }