/// <summary> /// Destroys the filtergraph releasing unmanaged resources. /// </summary> private void DestroyFiltergraph() { if (FilterGraph != null) { RC.Current.Remove(FilterGraph); fixed(AVFilterGraph **filterGraph = &FilterGraph) ffmpeg.avfilter_graph_free(filterGraph); FilterGraph = null; SinkInput = null; SourceOutput = null; } }
/// <summary> /// Destroys the filter graph releasing unmanaged resources. /// </summary> private void DestroyFilterGraph() { if (FilterGraph == null) { return; } RC.Current.Remove(FilterGraph); var filterGraphRef = FilterGraph; ffmpeg.avfilter_graph_free(&filterGraphRef); FilterGraph = null; SinkInput = null; SourceOutput = null; }
public VideoFlipperConverter(int width, int height, AVPixelFormat inputPixelFormat, StreamerSettings settings) { string filters = $"buffer=width={width}:height={height}:pix_fmt={(int)inputPixelFormat}:time_base=1/1:pixel_aspect=1/1 [in]; [out] buffersink;[in] format=pix_fmts=0 [in1];"; int inputCount = 1; if (settings.FlipY) { filters += $"[in{inputCount}] vflip [in{++inputCount}];"; } if (settings.FlipX) { filters += $"[in{inputCount}] hflip [in{++inputCount}];"; } filters += $"[in{inputCount}] copy [out]"; AVFilterInOut *gis = null; AVFilterInOut *gos = null; _filterGraph = ffmpeg.avfilter_graph_alloc(); ffmpeg.avfilter_graph_parse2(_filterGraph, filters, &gis, &gos).ThrowExceptionIfError(); ffmpeg.avfilter_graph_config(_filterGraph, null).ThrowExceptionIfError(); _filterSourceContext = ffmpeg.avfilter_graph_get_filter(_filterGraph, "Parsed_buffer_0"); _filterSinkContext = ffmpeg.avfilter_graph_get_filter(_filterGraph, "Parsed_buffersink_1"); if (_filterSourceContext == null || _filterSinkContext == null) { throw new Exception("Failed to create filter sinks"); } _flippedFrame = ffmpeg.av_frame_alloc(); var flippedFrameBuffer = (byte *)ffmpeg.av_malloc((ulong)ffmpeg.av_image_get_buffer_size(AVPixelFormat.AV_PIX_FMT_YUV420P, width, height, 1)); var dataArr = new byte_ptrArray4(); dataArr.UpdateFrom(_flippedFrame->data); var linesizeArr = new int_array4(); linesizeArr.UpdateFrom(_flippedFrame->linesize); ffmpeg.av_image_fill_arrays(ref dataArr, ref linesizeArr, flippedFrameBuffer, AVPixelFormat.AV_PIX_FMT_YUV420P, width, height, 1); _flippedFrame->data.UpdateFrom(dataArr); _flippedFrame->linesize.UpdateFrom(linesizeArr); }
public static MediaFilterGraph CreateMediaFilterGraph(string graphDesc) { MediaFilterGraph filterGraph = new MediaFilterGraph(); AVFilterInOut * inputs; AVFilterInOut * outputs; ffmpeg.avfilter_graph_parse2(filterGraph, graphDesc, &inputs, &outputs).ThrowExceptionIfError(); AVFilterInOut *cur = inputs; for (cur = inputs; cur != null; cur = cur->next) { Trace.TraceInformation($"{((IntPtr)cur->name).PtrToStringUTF8()}"); filterGraph.inputs.Add(new MediaFilterContext(cur->filter_ctx)); } for (cur = outputs; cur != null; cur = cur->next) { Trace.TraceInformation($"{((IntPtr)cur->name).PtrToStringUTF8()}"); filterGraph.outputs.Add(new MediaFilterContext(cur->filter_ctx)); } foreach (var item in filterGraph) { Trace.TraceInformation($"{item.Name}"); for (int i = 0; i < item.NbInputs; i++) { Trace.TraceInformation(ffmpeg.avfilter_pad_get_name(item.AVFilterContext.input_pads, i)); } Trace.TraceInformation("++++"); for (int i = 0; i < item.NbOutputs; i++) { Trace.TraceInformation(ffmpeg.avfilter_pad_get_name(item.AVFilterContext.output_pads, i)); } Trace.TraceInformation("---------"); } // TODO: Link filterGraph.Initialize(); ffmpeg.avfilter_inout_free(&inputs); ffmpeg.avfilter_inout_free(&outputs); return(filterGraph); }
private void DestroyFilterGraph() { try { if (FilterGraph == null) { return; } RC.Current.Remove(FilterGraph); var filterGraphRef = FilterGraph; ffmpeg.avfilter_graph_free(&filterGraphRef); FilterGraph = null; SinkInput = null; SourceOutput = null; } finally { AppliedFilterString = null; CurrentFilterArguments = null; } }
public static MediaFilterGraph CreateMediaFilterGraph(string graphDesc) { unsafe { MediaFilterGraph filterGraph = new MediaFilterGraph(); AVFilterInOut * inputs; AVFilterInOut * outputs; ffmpeg.avfilter_graph_parse2(filterGraph, graphDesc, &inputs, &outputs).ThrowExceptionIfError(); AVFilterInOut *cur = inputs; for (cur = inputs; cur != null; cur = cur->next) { ffmpeg.av_log(null, (int)LogLevel.Debug, $"{((IntPtr)cur->name).PtrToStringUTF8()}{Environment.NewLine}"); filterGraph.inputs.Add(new MediaFilterContext(cur->filter_ctx)); } for (cur = outputs; cur != null; cur = cur->next) { ffmpeg.av_log(null, (int)LogLevel.Debug, $"{((IntPtr)cur->name).PtrToStringUTF8()}{Environment.NewLine}"); filterGraph.outputs.Add(new MediaFilterContext(cur->filter_ctx)); } foreach (var item in filterGraph) { ffmpeg.av_log(null, (int)LogLevel.Debug, $"{item.Name}{Environment.NewLine}"); for (int i = 0; i < item.NbInputs; i++) { ffmpeg.av_log(null, (int)LogLevel.Debug, $"{ffmpeg.avfilter_pad_get_name(item.AVFilterContext.input_pads, i)}{Environment.NewLine}"); } for (int i = 0; i < item.NbOutputs; i++) { ffmpeg.av_log(null, (int)LogLevel.Debug, $"{ffmpeg.avfilter_pad_get_name(item.AVFilterContext.output_pads, i)}{Environment.NewLine}"); } } // TODO: Link filterGraph.Initialize(); ffmpeg.avfilter_inout_free(&inputs); ffmpeg.avfilter_inout_free(&outputs); return(filterGraph); } }
/// <summary> /// If necessary, disposes the existing filtergraph and creates a new one based on the frame arguments. /// </summary> /// <param name="frame">The frame.</param> /// <exception cref="MediaContainerException"> /// avfilter_graph_create_filter /// or /// avfilter_graph_create_filter /// or /// avfilter_link /// or /// avfilter_graph_parse /// or /// avfilter_graph_config /// </exception> private void InitializeFilterGraph(AVFrame *frame) { /* * References: * https://www.ffmpeg.org/doxygen/2.0/doc_2examples_2filtering_audio_8c-example.html */ var frameArguments = ComputeFilterArguments(frame); if (string.IsNullOrWhiteSpace(CurrentFilterArguments) || frameArguments.Equals(CurrentFilterArguments) == false) { DestroyFiltergraph(); } else { return; } FilterGraph = ffmpeg.avfilter_graph_alloc(); RC.Current.Add(FilterGraph, $"264: {nameof(AudioComponent)}.{nameof(InitializeFilterGraph)}()"); CurrentFilterArguments = frameArguments; try { var result = 0; fixed(AVFilterContext **source = &SourceFilter) fixed(AVFilterContext **sink = &SinkFilter) { result = ffmpeg.avfilter_graph_create_filter(source, ffmpeg.avfilter_get_by_name("abuffer"), "audio_buffer", CurrentFilterArguments, null, FilterGraph); if (result != 0) { throw new MediaContainerException( $"{nameof(ffmpeg.avfilter_graph_create_filter)} (audio_buffer) failed. Error {result}: {FFmpegEx.GetErrorMessage(result)}"); } result = ffmpeg.avfilter_graph_create_filter(sink, ffmpeg.avfilter_get_by_name("abuffersink"), "audio_buffersink", null, null, FilterGraph); if (result != 0) { throw new MediaContainerException( $"{nameof(ffmpeg.avfilter_graph_create_filter)} (audio_buffersink) failed. Error {result}: {FFmpegEx.GetErrorMessage(result)}"); } } if (string.IsNullOrWhiteSpace(FilterString)) { result = ffmpeg.avfilter_link(SourceFilter, 0, SinkFilter, 0); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_link)} failed. Error {result}: {FFmpegEx.GetErrorMessage(result)}"); } } else { var initFilterCount = FilterGraph->nb_filters; SourceOutput = ffmpeg.avfilter_inout_alloc(); SourceOutput->name = ffmpeg.av_strdup("in"); SourceOutput->filter_ctx = SourceFilter; SourceOutput->pad_idx = 0; SourceOutput->next = null; SinkInput = ffmpeg.avfilter_inout_alloc(); SinkInput->name = ffmpeg.av_strdup("out"); SinkInput->filter_ctx = SinkFilter; SinkInput->pad_idx = 0; SinkInput->next = null; result = ffmpeg.avfilter_graph_parse(FilterGraph, FilterString, SinkInput, SourceOutput, null); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_graph_parse)} failed. Error {result}: {FFmpegEx.GetErrorMessage(result)}"); } // Reorder the filters to ensure that inputs of the custom filters are merged first for (var i = 0; i < FilterGraph->nb_filters - initFilterCount; i++) { var sourceAddress = FilterGraph->filters[i]; var targetAddress = FilterGraph->filters[i + initFilterCount]; FilterGraph->filters[i] = targetAddress; FilterGraph->filters[i + initFilterCount] = sourceAddress; } } result = ffmpeg.avfilter_graph_config(FilterGraph, null); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_graph_config)} failed. Error {result}: {FFmpegEx.GetErrorMessage(result)}"); } } catch (Exception ex) { Container.Logger?.Log(MediaLogMessageType.Error, $"Audio filter graph could not be built: {FilterString}.\r\n{ex.Message}"); DestroyFiltergraph(); } }
/// <summary> /// If necessary, disposes the existing filtergraph and creates a new one based on the frame arguments. /// </summary> /// <param name="frame">The frame.</param> /// <exception cref="MediaContainerException"> /// avfilter_graph_create_filter /// or /// avfilter_graph_create_filter /// or /// avfilter_link /// or /// avfilter_graph_parse /// or /// avfilter_graph_config /// </exception> private void InitializeFilterGraph(AVFrame *frame) { /* * References: * http://libav-users.943685.n4.nabble.com/Libav-user-yadif-deinterlace-how-td3606561.html * https://www.ffmpeg.org/doxygen/trunk/filtering_8c-source.html * https://raw.githubusercontent.com/FFmpeg/FFmpeg/release/3.2/ffplay.c */ var frameArguments = ComputeFilterArguments(frame); if (string.IsNullOrWhiteSpace(CurrentFilterArguments) || frameArguments.Equals(CurrentFilterArguments) == false) { DestroyFiltergraph(); } else { return; } FilterGraph = ffmpeg.avfilter_graph_alloc(); RC.Current.Add(FilterGraph, $"144: {nameof(VideoComponent)}.{nameof(InitializeFilterGraph)}()"); CurrentFilterArguments = frameArguments; try { var result = 0; fixed(AVFilterContext **source = &SourceFilter) fixed(AVFilterContext **sink = &SinkFilter) { result = ffmpeg.avfilter_graph_create_filter(source, ffmpeg.avfilter_get_by_name("buffer"), "video_buffer", CurrentFilterArguments, null, FilterGraph); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_graph_create_filter)} (buffer) failed. Error {result}: {Utils.DecodeFFmpegMessage(result)}"); } result = ffmpeg.avfilter_graph_create_filter(sink, ffmpeg.avfilter_get_by_name("buffersink"), "video_buffersink", null, null, FilterGraph); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_graph_create_filter)} (buffersink) failed. Error {result}: {Utils.DecodeFFmpegMessage(result)}"); } // TODO: from ffplay, ffmpeg.av_opt_set_int_list(sink, "pix_fmts", (byte*)&f0, 1, ffmpeg.AV_OPT_SEARCH_CHILDREN); } if (string.IsNullOrWhiteSpace(FilterString)) { result = ffmpeg.avfilter_link(SourceFilter, 0, SinkFilter, 0); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_link)} failed. Error {result}: {Utils.DecodeFFmpegMessage(result)}"); } } else { var initFilterCount = FilterGraph->nb_filters; SourceOutput = ffmpeg.avfilter_inout_alloc(); SourceOutput->name = ffmpeg.av_strdup("in"); SourceOutput->filter_ctx = SourceFilter; SourceOutput->pad_idx = 0; SourceOutput->next = null; SinkInput = ffmpeg.avfilter_inout_alloc(); SinkInput->name = ffmpeg.av_strdup("out"); SinkInput->filter_ctx = SinkFilter; SinkInput->pad_idx = 0; SinkInput->next = null; result = ffmpeg.avfilter_graph_parse(FilterGraph, FilterString, SinkInput, SourceOutput, null); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_graph_parse)} failed. Error {result}: {Utils.DecodeFFmpegMessage(result)}"); } // Reorder the filters to ensure that inputs of the custom filters are merged first for (var i = 0; i < FilterGraph->nb_filters - initFilterCount; i++) { var sourceAddress = FilterGraph->filters[i]; var targetAddress = FilterGraph->filters[i + initFilterCount]; FilterGraph->filters[i] = targetAddress; FilterGraph->filters[i + initFilterCount] = sourceAddress; } } result = ffmpeg.avfilter_graph_config(FilterGraph, null); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_graph_config)} failed. Error {result}: {Utils.DecodeFFmpegMessage(result)}"); } } catch (Exception ex) { Container.Logger?.Log(MediaLogMessageType.Error, $"Video filter graph could not be built: {FilterString}.\r\n{ex.Message}"); DestroyFiltergraph(); } }
private void InitializeFilterGraph(AVFrame *frame) { // References: https://www.ffmpeg.org/doxygen/2.0/doc_2examples_2filtering_audio_8c-example.html const string SourceFilterName = "abuffer"; const string SourceFilterInstance = "audio_buffer"; const string SinkFilterName = "abuffersink"; const string SinkFilterInstance = "audio_buffersink"; // Get a snapshot of the FilterString var filterString = FilterString; // For empty filter strings ensure filtegraph is destroyed if (string.IsNullOrWhiteSpace(filterString)) { DestroyFilterGraph(); return; } // Recreate the filtergraph if we have to if (filterString != AppliedFilterString) { DestroyFilterGraph(); } // Ensure the filtergraph is compatible with the frame var filterArguments = ComputeFilterArguments(frame); if (filterArguments != CurrentFilterArguments) { DestroyFilterGraph(); } else { return; } FilterGraph = ffmpeg.avfilter_graph_alloc(); RC.Current.Add(FilterGraph); try { AVFilterContext *sourceFilterRef = null; AVFilterContext *sinkFilterRef = null; var result = ffmpeg.avfilter_graph_create_filter( &sourceFilterRef, ffmpeg.avfilter_get_by_name(SourceFilterName), SourceFilterInstance, filterArguments, null, FilterGraph); if (result != 0) { throw new MediaContainerException( $"{nameof(ffmpeg.avfilter_graph_create_filter)} ({SourceFilterInstance}) failed. Error {result}: {FFInterop.DecodeMessage(result)}"); } result = ffmpeg.avfilter_graph_create_filter( &sinkFilterRef, ffmpeg.avfilter_get_by_name(SinkFilterName), SinkFilterInstance, null, null, FilterGraph); if (result != 0) { throw new MediaContainerException( $"{nameof(ffmpeg.avfilter_graph_create_filter)} ({SinkFilterInstance}) failed. Error {result}: {FFInterop.DecodeMessage(result)}"); } SourceFilter = sourceFilterRef; SinkFilter = sinkFilterRef; if (string.IsNullOrWhiteSpace(filterString)) { result = ffmpeg.avfilter_link(SourceFilter, 0, SinkFilter, 0); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_link)} failed. Error {result}: {FFInterop.DecodeMessage(result)}"); } } else { var initFilterCount = FilterGraph->nb_filters; SourceOutput = ffmpeg.avfilter_inout_alloc(); SourceOutput->name = ffmpeg.av_strdup("in"); SourceOutput->filter_ctx = SourceFilter; SourceOutput->pad_idx = 0; SourceOutput->next = null; SinkInput = ffmpeg.avfilter_inout_alloc(); SinkInput->name = ffmpeg.av_strdup("out"); SinkInput->filter_ctx = SinkFilter; SinkInput->pad_idx = 0; SinkInput->next = null; result = ffmpeg.avfilter_graph_parse(FilterGraph, filterString, SinkInput, SourceOutput, null); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_graph_parse)} failed. Error {result}: {FFInterop.DecodeMessage(result)}"); } // Reorder the filters to ensure that inputs of the custom filters are merged first for (var i = 0; i < FilterGraph->nb_filters - initFilterCount; i++) { var sourceAddress = FilterGraph->filters[i]; var targetAddress = FilterGraph->filters[i + initFilterCount]; FilterGraph->filters[i] = targetAddress; FilterGraph->filters[i + initFilterCount] = sourceAddress; } } result = ffmpeg.avfilter_graph_config(FilterGraph, null); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_graph_config)} failed. Error {result}: {FFInterop.DecodeMessage(result)}"); } } catch (Exception ex) { this.LogError(Aspects.Component, $"Audio filter graph could not be built: {filterString}.", ex); DestroyFilterGraph(); } finally { CurrentFilterArguments = filterArguments; AppliedFilterString = filterString; } }
public static extern int avfilter_graph_parse(AVFilterGraph * @graph, [MarshalAs(UnmanagedType.LPStr)] string @filters, AVFilterInOut * @inputs, AVFilterInOut * @outputs, void * @log_ctx);
private void InitializeFilterGraph(AVFrame *frame) { /* * References: * http://libav-users.943685.n4.nabble.com/Libav-user-yadif-deinterlace-how-td3606561.html * https://www.ffmpeg.org/doxygen/trunk/filtering_8c-source.html * https://raw.githubusercontent.com/FFmpeg/FFmpeg/release/3.2/ffplay.c */ const string SourceFilterName = "buffer"; const string SourceFilterInstance = "video_buffer"; const string SinkFilterName = "buffersink"; const string SinkFilterInstance = "video_buffersink"; // Get a snapshot of the FilterString var filterString = FilterString; // For empty filter strings ensure filtegraph is destroyed if (string.IsNullOrWhiteSpace(filterString)) { DestroyFilterGraph(); return; } // Recreate the filtergraph if we have to if (filterString != AppliedFilterString) { DestroyFilterGraph(); } // Ensure the filtergraph is compatible with the frame var filterArguments = ComputeFilterArguments(frame); if (filterArguments != CurrentFilterArguments) { DestroyFilterGraph(); } else { return; } FilterGraph = ffmpeg.avfilter_graph_alloc(); RC.Current.Add(FilterGraph); try { // Get a couple of pointers for source and sink buffers AVFilterContext *sourceFilterRef = null; AVFilterContext *sinkFilterRef = null; // Create the source filter var result = ffmpeg.avfilter_graph_create_filter( &sourceFilterRef, ffmpeg.avfilter_get_by_name(SourceFilterName), SourceFilterInstance, filterArguments, null, FilterGraph); // Check filter creation if (result != 0) { throw new MediaContainerException( $"{nameof(ffmpeg.avfilter_graph_create_filter)} ({SourceFilterName}) failed. " + $"Error {result}: {FFInterop.DecodeMessage(result)}"); } // Create the sink filter result = ffmpeg.avfilter_graph_create_filter( &sinkFilterRef, ffmpeg.avfilter_get_by_name(SinkFilterName), SinkFilterInstance, null, null, FilterGraph); // Check filter creation if (result != 0) { throw new MediaContainerException( $"{nameof(ffmpeg.avfilter_graph_create_filter)} ({SinkFilterName}) failed. " + $"Error {result}: {FFInterop.DecodeMessage(result)}"); } // Save the filter references SourceFilter = sourceFilterRef; SinkFilter = sinkFilterRef; // TODO: from ffplay, ffmpeg.av_opt_set_int_list(sink, "pixel_formats", (byte*)&f0, 1, ffmpeg.AV_OPT_SEARCH_CHILDREN) if (string.IsNullOrWhiteSpace(filterString)) { result = ffmpeg.avfilter_link(SourceFilter, 0, SinkFilter, 0); if (result != 0) { throw new MediaContainerException( $"{nameof(ffmpeg.avfilter_link)} failed. " + $"Error {result}: {FFInterop.DecodeMessage(result)}"); } } else { var initFilterCount = FilterGraph->nb_filters; SourceOutput = ffmpeg.avfilter_inout_alloc(); SourceOutput->name = ffmpeg.av_strdup("in"); SourceOutput->filter_ctx = SourceFilter; SourceOutput->pad_idx = 0; SourceOutput->next = null; SinkInput = ffmpeg.avfilter_inout_alloc(); SinkInput->name = ffmpeg.av_strdup("out"); SinkInput->filter_ctx = SinkFilter; SinkInput->pad_idx = 0; SinkInput->next = null; result = ffmpeg.avfilter_graph_parse(FilterGraph, filterString, SinkInput, SourceOutput, null); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_graph_parse)} failed. Error {result}: {FFInterop.DecodeMessage(result)}"); } // Reorder the filters to ensure that inputs of the custom filters are merged first for (var i = 0; i < FilterGraph->nb_filters - initFilterCount; i++) { var sourceAddress = FilterGraph->filters[i]; var targetAddress = FilterGraph->filters[i + initFilterCount]; FilterGraph->filters[i] = targetAddress; FilterGraph->filters[i + initFilterCount] = sourceAddress; } } result = ffmpeg.avfilter_graph_config(FilterGraph, null); if (result != 0) { throw new MediaContainerException($"{nameof(ffmpeg.avfilter_graph_config)} failed. Error {result}: {FFInterop.DecodeMessage(result)}"); } } catch (Exception ex) { this.LogError(Aspects.Component, $"Video filter graph could not be built: {filterString}.", ex); DestroyFilterGraph(); } finally { CurrentFilterArguments = filterArguments; AppliedFilterString = filterString; } }
unsafe public void InitFilter(AVFilterGraph *_filter_graph, String filter_desc, AVFilterContext *_filter_ctx_src_spk, AVFilterContext *_filter_ctx_src_mic, AVFilterContext *_filter_ctx_sink, Openfile openfile1, Openfile openfile2, Openfile outfile) { AVFilter *filter_src_spk = ffmpeg.avfilter_get_by_name("abuffer"); AVFilter *filter_src_mic = ffmpeg.avfilter_get_by_name("abuffer"); AVFilter *filter_sink = ffmpeg.avfilter_get_by_name("abuffersink"); AVFilterInOut *filter_output_spk = ffmpeg.avfilter_inout_alloc(); AVFilterInOut *filter_output_mic = ffmpeg.avfilter_inout_alloc(); AVFilterInOut *filter_input = ffmpeg.avfilter_inout_alloc(); _filter_graph = ffmpeg.avfilter_graph_alloc(); string args_spk = "time_base=1/44100:sample_rate=44100:sample_fmt=8:channel_layout=3"; // 5.1 创建输出滤镜的上下文 //_filter_ctx_sink = ffmpeg.avfilter_graph_alloc_filter(_filter_graph, filter_sink, "sink"); int ret = ffmpeg.avfilter_graph_create_filter(&_filter_ctx_src_spk, filter_src_spk, "in0", args_spk, null, _filter_graph); ret = ffmpeg.avfilter_graph_create_filter(&_filter_ctx_src_mic, filter_src_mic, "in1", args_spk, null, _filter_graph); ret = ffmpeg.avfilter_graph_create_filter(&_filter_ctx_sink, filter_sink, "out", null, null, _filter_graph); AVCodecContext *encodec_ctx = outfile._pCodecContext; //过滤器上下文输出参数配置 //ret = ffmpeg.av_opt_set_bin(_filter_ctx_sink, "sample_rates", (byte*)outfile._pCodecContext->sample_rate, (int)8, 1); //if (ret < 0) //{ // Console.WriteLine("Filter: failed to call av_opt_set_bin -- sample_rates\n"); //} ret = ffmpeg.av_opt_set_bin(_filter_ctx_sink, "sample_fmts", (byte *)&encodec_ctx->sample_fmt, (int)8, 1); if (ret < 0) { Console.WriteLine("Filter: failed to call av_opt_set_bin -- sample_fmts\n"); } ret = ffmpeg.av_opt_set_bin(_filter_ctx_sink, "channel_layouts", (byte *)&encodec_ctx->channel_layout, (int)8, 1); if (ret < 0) { Console.WriteLine("Filter: failed to call av_opt_set_bin -- channel_layouts\n"); } ret = ffmpeg.av_opt_set_bin(_filter_ctx_src_spk, "sample_fmts", (byte *)&encodec_ctx->sample_fmt, (int)8, 1); if (ret < 0) { Console.WriteLine("Filter: failed to call _filter_ctx_src_spk -- sample_fmts\n"); } filter_output_spk->name = ffmpeg.av_strdup("in0"); filter_output_spk->filter_ctx = _filter_ctx_src_spk; filter_output_spk->pad_idx = 0; filter_output_spk->next = filter_output_mic; filter_output_mic->name = ffmpeg.av_strdup("in1"); filter_output_mic->filter_ctx = _filter_ctx_src_mic; filter_output_mic->pad_idx = 0; filter_output_mic->next = null; filter_input->name = ffmpeg.av_strdup("out"); filter_input->filter_ctx = _filter_ctx_sink; filter_input->pad_idx = 0; filter_input->next = null; AVFilterInOut *[] filter_outputs = new AVFilterInOut *[2]; filter_outputs[0] = filter_output_spk; filter_outputs[1] = filter_output_mic; fixed(AVFilterInOut **outs = &filter_outputs[0]) { ret = ffmpeg.avfilter_graph_parse_ptr(_filter_graph, filter_desc, &filter_input, outs, null); ret = ffmpeg.avfilter_graph_config(_filter_graph, null); if (ret < 0) { Console.WriteLine("Filter: failed to call avfilter_graph_config -- avfilter_graph_config\n"); } byte *ff = ffmpeg.avfilter_graph_dump(_filter_graph, null); Console.WriteLine("Filter: failed to call avfilter_graph_dump -- avfilter_graph_dump\n" + *ff); } this._filter_ctx_src_spk = _filter_ctx_src_spk; this._filter_ctx_src_mic = _filter_ctx_src_mic; this._filter_ctx_sink = _filter_ctx_sink; }
public extern static int avfilter_graph_parse(AVFilterGraph *graph, [MarshalAs(UnmanagedType.LPStr)] string filters, AVFilterInOut *inputs, AVFilterInOut *outputs, void *log_ctx);