You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	avfiltergraph: add avfilter_graph_request_oldest().
Keep a heap of all sink links ordered by timestamps.
This commit is contained in:
		| @@ -278,6 +278,8 @@ int avfilter_config_links(AVFilterContext *filter) | ||||
|  | ||||
|         if (!link) continue; | ||||
|  | ||||
|         link->current_pts = AV_NOPTS_VALUE; | ||||
|  | ||||
|         switch (link->init_state) { | ||||
|         case AVLINK_INIT: | ||||
|             continue; | ||||
| @@ -568,6 +570,15 @@ int avfilter_poll_frame(AVFilterLink *link) | ||||
|     return min; | ||||
| } | ||||
|  | ||||
| static void update_link_current_pts(AVFilterLink *link) | ||||
| { | ||||
|     if (link->cur_buf->pts == AV_NOPTS_VALUE) | ||||
|         return; | ||||
|     link->current_pts =  link->cur_buf->pts; /* TODO use duration */ | ||||
|     if (link->graph && link->age_index >= 0) | ||||
|         ff_avfilter_graph_update_heap(link->graph, link); | ||||
| } | ||||
|  | ||||
| /* XXX: should we do the duplicating of the picture ref here, instead of | ||||
|  * forcing the source filter to do it? */ | ||||
| void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | ||||
| @@ -608,6 +619,7 @@ void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | ||||
|     } | ||||
|  | ||||
|     start_frame(link, link->cur_buf); | ||||
|     update_link_current_pts(link); | ||||
| } | ||||
|  | ||||
| void avfilter_end_frame(AVFilterLink *link) | ||||
| @@ -712,6 +724,7 @@ void avfilter_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) | ||||
|         link->cur_buf = samplesref; | ||||
|  | ||||
|     filter_samples(link, link->cur_buf); | ||||
|     update_link_current_pts(link); | ||||
| } | ||||
|  | ||||
| #define MAX_REGISTERED_AVFILTERS_NB 128 | ||||
|   | ||||
| @@ -696,6 +696,23 @@ struct AVFilterLink { | ||||
|      */ | ||||
|     struct AVFilterGraph *graph; | ||||
|  | ||||
|     /** | ||||
|      * Current timestamp of the link, as defined by the most recent | ||||
|      * frame(s), in AV_TIME_BASE units. | ||||
|      */ | ||||
|     int64_t current_pts; | ||||
|  | ||||
|     /** | ||||
|      * Private fields | ||||
|      * | ||||
|      * The following fields are for internal use only. | ||||
|      * Their type, offset, number and semantic can change without notice. | ||||
|      */ | ||||
|  | ||||
|     /** | ||||
|      * Index in the age array. | ||||
|      */ | ||||
|     int age_index; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -24,6 +24,7 @@ | ||||
| #include <string.h> | ||||
|  | ||||
| #include "libavutil/audioconvert.h" | ||||
| #include "libavutil/avassert.h" | ||||
| #include "libavutil/pixdesc.h" | ||||
| #include "avfilter.h" | ||||
| #include "avfiltergraph.h" | ||||
| @@ -374,19 +375,46 @@ int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx) | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static void ff_avfilter_graph_config_pointers(AVFilterGraph *graph, | ||||
|                                               AVClass *log_ctx) | ||||
| static int ff_avfilter_graph_config_pointers(AVFilterGraph *graph, | ||||
|                                              AVClass *log_ctx) | ||||
| { | ||||
|     unsigned i, j;; | ||||
|     unsigned i, j; | ||||
|     int sink_links_count = 0, n = 0; | ||||
|     AVFilterContext *f; | ||||
|     AVFilterLink **sinks; | ||||
|  | ||||
|     for (i = 0; i < graph->filter_count; i++) { | ||||
|         f = graph->filters[i]; | ||||
|         for (j = 0; j < f->input_count; j++) | ||||
|             f->inputs[j]->graph = graph; | ||||
|         for (j = 0; j < f->output_count; j++) | ||||
|             f->outputs[j]->graph = graph; | ||||
|         for (j = 0; j < f->input_count; j++) { | ||||
|             f->inputs[j]->graph     = graph; | ||||
|             f->inputs[j]->age_index = -1; | ||||
|         } | ||||
|         for (j = 0; j < f->output_count; j++) { | ||||
|             f->outputs[j]->graph    = graph; | ||||
|             f->outputs[j]->age_index= -1; | ||||
|         } | ||||
|         if (!f->output_count) { | ||||
|             if (f->input_count > INT_MAX - sink_links_count) | ||||
|                 return AVERROR(EINVAL); | ||||
|             sink_links_count += f->input_count; | ||||
|         } | ||||
|     } | ||||
|     sinks = av_calloc(sink_links_count, sizeof(*sinks)); | ||||
|     if (!sinks) | ||||
|         return AVERROR(ENOMEM); | ||||
|     for (i = 0; i < graph->filter_count; i++) { | ||||
|         f = graph->filters[i]; | ||||
|         if (!f->output_count) { | ||||
|             for (j = 0; j < f->input_count; j++) { | ||||
|                 sinks[n] = f->inputs[j]; | ||||
|                 f->inputs[j]->age_index = n++; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     av_assert0(n == sink_links_count); | ||||
|     graph->sink_links       = sinks; | ||||
|     graph->sink_links_count = sink_links_count; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx) | ||||
| @@ -399,7 +427,8 @@ int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx) | ||||
|         return ret; | ||||
|     if ((ret = ff_avfilter_graph_config_links(graphctx, log_ctx))) | ||||
|         return ret; | ||||
|     ff_avfilter_graph_config_pointers(graphctx, log_ctx); | ||||
|     if ((ret = ff_avfilter_graph_config_pointers(graphctx, log_ctx))) | ||||
|         return ret; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| @@ -461,3 +490,65 @@ int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static void heap_bubble_up(AVFilterGraph *graph, | ||||
|                            AVFilterLink *link, int index) | ||||
| { | ||||
|     AVFilterLink **links = graph->sink_links; | ||||
|  | ||||
|     while (index) { | ||||
|         int parent = (index - 1) >> 1; | ||||
|         if (links[parent]->current_pts >= link->current_pts) | ||||
|             break; | ||||
|         links[index] = links[parent]; | ||||
|         links[index]->age_index = index; | ||||
|         index = parent; | ||||
|     } | ||||
|     links[index] = link; | ||||
|     link->age_index = index; | ||||
| } | ||||
|  | ||||
| static void heap_bubble_down(AVFilterGraph *graph, | ||||
|                              AVFilterLink *link, int index) | ||||
| { | ||||
|     AVFilterLink **links = graph->sink_links; | ||||
|  | ||||
|     while (1) { | ||||
|         int child = 2 * index + 1; | ||||
|         if (child >= graph->sink_links_count) | ||||
|             break; | ||||
|         if (child + 1 < graph->sink_links_count && | ||||
|             links[child + 1]->current_pts < links[child]->current_pts) | ||||
|             child++; | ||||
|         if (link->current_pts < links[child]->current_pts) | ||||
|             break; | ||||
|         links[index] = links[child]; | ||||
|         links[index]->age_index = index; | ||||
|         index = child; | ||||
|     } | ||||
|     links[index] = link; | ||||
|     link->age_index = index; | ||||
| } | ||||
|  | ||||
| void ff_avfilter_graph_update_heap(AVFilterGraph *graph, AVFilterLink *link) | ||||
| { | ||||
|     heap_bubble_up  (graph, link, link->age_index); | ||||
|     heap_bubble_down(graph, link, link->age_index); | ||||
| } | ||||
|  | ||||
|  | ||||
| int avfilter_graph_request_oldest(AVFilterGraph *graph) | ||||
| { | ||||
|     while (graph->sink_links_count) { | ||||
|         AVFilterLink *oldest = graph->sink_links[0]; | ||||
|         int r = avfilter_request_frame(oldest); | ||||
|         if (r != AVERROR_EOF) | ||||
|             return r; | ||||
|         /* EOF: remove the link from the heap */ | ||||
|         if (oldest->age_index < --graph->sink_links_count) | ||||
|             heap_bubble_down(graph, graph->sink_links[graph->sink_links_count], | ||||
|                              oldest->age_index); | ||||
|         oldest->age_index = -1; | ||||
|     } | ||||
|     return AVERROR_EOF; | ||||
| } | ||||
|   | ||||
| @@ -33,6 +33,16 @@ typedef struct AVFilterGraph { | ||||
|     AVFilterContext **filters; | ||||
|  | ||||
|     char *scale_sws_opts; ///< sws options to use for the auto-inserted scale filters | ||||
|  | ||||
|     /** | ||||
|      * Private fields | ||||
|      * | ||||
|      * The following fields are for internal use only. | ||||
|      * Their type, offset, number and semantic can change without notice. | ||||
|      */ | ||||
|  | ||||
|     AVFilterLink **sink_links; | ||||
|     int sink_links_count; | ||||
| } AVFilterGraph; | ||||
|  | ||||
| /** | ||||
| @@ -221,4 +231,18 @@ int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const | ||||
|  */ | ||||
| char *avfilter_graph_dump(AVFilterGraph *graph, const char *options); | ||||
|  | ||||
| /** | ||||
|  * Request a frame on the oldest sink link. | ||||
|  * | ||||
|  * If the request returns AVERROR_EOF, try the next. | ||||
|  * | ||||
|  * Note that this function is not meant to be the sole scheduling mechanism | ||||
|  * of a filtergraph, only a convenience function to help drain a filtergraph | ||||
|  * in a balanced way under normal circumstances. | ||||
|  * | ||||
|  * @return  the return value of avfilter_request_frame, | ||||
|  *          or AVERROR_EOF of all links returned AVERROR_EOF. | ||||
|  */ | ||||
| int avfilter_graph_request_oldest(AVFilterGraph *graph); | ||||
|  | ||||
| #endif /* AVFILTER_AVFILTERGRAPH_H */ | ||||
|   | ||||
| @@ -65,6 +65,11 @@ int ff_avfilter_graph_config_links(AVFilterGraph *graphctx, AVClass *log_ctx); | ||||
|  */ | ||||
| int ff_avfilter_graph_config_formats(AVFilterGraph *graphctx, AVClass *log_ctx); | ||||
|  | ||||
| /** | ||||
|  * Update the position of a link in the age heap. | ||||
|  */ | ||||
| void ff_avfilter_graph_update_heap(AVFilterGraph *graph, AVFilterLink *link); | ||||
|  | ||||
| /** default handler for freeing audio/video buffer when there are no references left */ | ||||
| void ff_avfilter_default_free_buffer(AVFilterBuffer *buf); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user