• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 /**
20  * @file
21  * Libavfilter multithreading support
22  */
23 
24 #include <stddef.h>
25 
26 #include "libavutil/error.h"
27 #include "libavutil/macros.h"
28 #include "libavutil/mem.h"
29 #include "libavutil/slicethread.h"
30 
31 #include "avfilter.h"
32 #include "internal.h"
33 #include "thread.h"
34 
35 typedef struct ThreadContext {
36     AVFilterGraph *graph;
37     AVSliceThread *thread;
38     avfilter_action_func *func;
39 
40     /* per-execute parameters */
41     AVFilterContext *ctx;
42     void *arg;
43     int   *rets;
44 } ThreadContext;
45 
worker_func(void * priv,int jobnr,int threadnr,int nb_jobs,int nb_threads)46 static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
47 {
48     ThreadContext *c = priv;
49     int ret = c->func(c->ctx, c->arg, jobnr, nb_jobs);
50     if (c->rets)
51         c->rets[jobnr] = ret;
52 }
53 
slice_thread_uninit(ThreadContext * c)54 static void slice_thread_uninit(ThreadContext *c)
55 {
56     avpriv_slicethread_free(&c->thread);
57 }
58 
thread_execute(AVFilterContext * ctx,avfilter_action_func * func,void * arg,int * ret,int nb_jobs)59 static int thread_execute(AVFilterContext *ctx, avfilter_action_func *func,
60                           void *arg, int *ret, int nb_jobs)
61 {
62     ThreadContext *c = ctx->graph->internal->thread;
63 
64     if (nb_jobs <= 0)
65         return 0;
66     c->ctx         = ctx;
67     c->arg         = arg;
68     c->func        = func;
69     c->rets        = ret;
70 
71     avpriv_slicethread_execute(c->thread, nb_jobs, 0);
72     return 0;
73 }
74 
thread_init_internal(ThreadContext * c,int nb_threads)75 static int thread_init_internal(ThreadContext *c, int nb_threads)
76 {
77     nb_threads = avpriv_slicethread_create(&c->thread, c, worker_func, NULL, nb_threads);
78     if (nb_threads <= 1)
79         avpriv_slicethread_free(&c->thread);
80     return FFMAX(nb_threads, 1);
81 }
82 
ff_graph_thread_init(AVFilterGraph * graph)83 int ff_graph_thread_init(AVFilterGraph *graph)
84 {
85     int ret;
86 
87     if (graph->nb_threads == 1) {
88         graph->thread_type = 0;
89         return 0;
90     }
91 
92     graph->internal->thread = av_mallocz(sizeof(ThreadContext));
93     if (!graph->internal->thread)
94         return AVERROR(ENOMEM);
95 
96     ret = thread_init_internal(graph->internal->thread, graph->nb_threads);
97     if (ret <= 1) {
98         av_freep(&graph->internal->thread);
99         graph->thread_type = 0;
100         graph->nb_threads  = 1;
101         return (ret < 0) ? ret : 0;
102     }
103     graph->nb_threads = ret;
104 
105     graph->internal->thread_execute = thread_execute;
106 
107     return 0;
108 }
109 
ff_graph_thread_free(AVFilterGraph * graph)110 void ff_graph_thread_free(AVFilterGraph *graph)
111 {
112     if (graph->internal->thread)
113         slice_thread_uninit(graph->internal->thread);
114     av_freep(&graph->internal->thread);
115 }
116