1 /*
2  * tcmodule-plugin.h -- transcode module system, take two: plugin parts.
3  * (C) 2005-2010 - Francesco Romani <fromani -at- gmail -dot- com>
4  *
5  * This file is part of transcode, a video stream processing tool.
6  *
7  * transcode is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * transcode is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 
22 #ifndef TCMODULE_PLUGIN_H
23 #define TCMODULE_PLUGIN_H
24 
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28 
29 #include <stdint.h>
30 
31 #include "tcmodule-info.h"
32 #include "tcmodule-data.h"
33 
34 
35 #define TC_MODULE_SELF_CHECK(self, WHERE) do { \
36     if ((self) == NULL) { \
37         tc_log_error(MOD_NAME, WHERE ": " # self " is NULL"); \
38         return TC_ERROR; /* catch all for filter/encoders/decoders/(de)muxers */ \
39     } \
40 } while (0)
41 
42 
43 #define TC_HAS_FEATURE(flags, feat) \
44     ((flags & (TC_MODULE_FEATURE_ ## feat)) ?1 :0)
45 
46 #ifdef HAVE_GCC_ATTRIBUTES
47 __attribute__((unused))
48 #endif
tc_module_av_check(uint32_t flags)49 static int tc_module_av_check(uint32_t flags)
50 {
51     int i = 0;
52 
53     i += TC_HAS_FEATURE(flags, AUDIO);
54     i += TC_HAS_FEATURE(flags, VIDEO);
55     i += TC_HAS_FEATURE(flags, EXTRA);
56 
57     return i;
58 }
59 
60 #ifdef HAVE_GCC_ATTRIBUTES
61 __attribute__((unused))
62 #endif
tc_module_cap_check(uint32_t flags)63 static int tc_module_cap_check(uint32_t flags)
64 {
65     int i = 0;
66 
67     i += TC_HAS_FEATURE(flags, DECODE);
68     i += TC_HAS_FEATURE(flags, FILTER);
69     i += TC_HAS_FEATURE(flags, ENCODE);
70     i += TC_HAS_FEATURE(flags, MULTIPLEX);
71     i += TC_HAS_FEATURE(flags, DEMULTIPLEX);
72 
73     return i;
74 }
75 
76 #undef TC_HAS_FEATURE
77 
78 
79 #define TC_MODULE_INIT_CHECK(self, FEATURES, feat) do { \
80     int j = tc_module_cap_check((feat)); \
81     \
82     if ((!((FEATURES) & TC_MODULE_FEATURE_MULTIPLEX) \
83       && !((FEATURES) & TC_MODULE_FEATURE_DEMULTIPLEX)) \
84      && (tc_module_av_check((feat)) > 1)) { \
85         tc_log_error(MOD_NAME, "unsupported stream types for" \
86                            " this module instance"); \
87     return TC_ERROR; \
88     } \
89     \
90     if (j != 0 && j != 1) { \
91         tc_log_error(MOD_NAME, "feature request mismatch for" \
92                            " this module instance (req=%i)", j); \
93     return TC_ERROR; \
94     } \
95     /* is perfectly fine to request to do nothing */ \
96     if ((feat != 0) && ((FEATURES) & (feat))) { \
97         (self)->features = (feat); \
98     } else { \
99         tc_log_error(MOD_NAME, "this module does not support" \
100                                " requested feature"); \
101         return TC_ERROR; \
102     } \
103 } while (0)
104 
105 /*
106  * autogeneration macros for generic init/fini pair
107  * looks like generic pair is needed often that expected;
108  * In future module system revision, maybe they will be
109  * moved into core.
110  */
111 
112 #define TC_MODULE_GENERIC_INIT(MODNAME, MODDATA) \
113     static int MODNAME ## _init(TCModuleInstance *self, uint32_t features) \
114     { \
115         MODDATA *pd = NULL; \
116         \
117         TC_MODULE_SELF_CHECK(self, "init"); \
118         TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features); \
119         \
120         pd = tc_malloc(sizeof(MODDATA)); \
121         if (pd == NULL) { \
122             tc_log_error(MOD_NAME, "init: out of memory!"); \
123             return TC_ERROR; \
124         } \
125         \
126         self->userdata = pd; \
127         \
128         if (verbose) { \
129             tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP); \
130         } \
131         \
132         return TC_OK; \
133     }
134 
135 #define TC_MODULE_GENERIC_FINI(MODNAME) \
136     static int MODNAME ## _fini(TCModuleInstance *self) \
137     { \
138         TC_MODULE_SELF_CHECK(self, "fini"); \
139         \
140         tc_free(self->userdata); \
141         self->userdata = NULL; \
142         return TC_OK; \
143     }
144 
145 /*
146  * autogeneration macro for TCModuleInfo descriptor
147  */
148 #define TC_MODULE_INFO(PREFIX) \
149 static const TCModuleInfo PREFIX ## _info = { \
150     .features    = MOD_FEATURES,          \
151     .flags       = MOD_FLAGS,             \
152     .name        = MOD_NAME,              \
153     .version     = MOD_VERSION,           \
154     .description = MOD_CAP,               \
155     .codecs_in   = PREFIX ## _codecs_in,  \
156     .codecs_out  = PREFIX ## _codecs_out, \
157     .formats_in  = PREFIX ## _formats_in, \
158     .formats_out = PREFIX ## _formats_out \
159 }
160 
161 /* please note the MISSING trailing comma */
162 #define TC_MODULE_CLASS_HEAD(PREFIX) \
163     .version     = TC_MODULE_VERSION,  \
164     .info        = & ( PREFIX ## _info)
165 
166 
167 /*
168  * autogeneration for supported codecs/multiplexors
169  */
170 #define TC_MODULE_FILTER_FORMATS(PREFIX) \
171 static const TCFormatID PREFIX ## _formats_in[]  = { TC_FORMAT_ERROR }; \
172 static const TCFormatID PREFIX ## _formats_out[] = { TC_FORMAT_ERROR }
173 
174 #define TC_MODULE_CODEC_FORMATS(PREFIX) \
175 static const TCFormatID PREFIX ## _formats_in[]  = { TC_FORMAT_ERROR }; \
176 static const TCFormatID PREFIX ## _formats_out[] = { TC_FORMAT_ERROR }
177 
178 #define TC_MODULE_MPLEX_FORMATS_CODECS(PREFIX) \
179 static const TCCodecID  PREFIX ## _codecs_out[] = { TC_CODEC_ERROR }; \
180 static const TCFormatID PREFIX ## _formats_in[] = { TC_FORMAT_ERROR }
181 
182 #define TC_MODULE_DEMUX_FORMATS_CODECS(PREFIX) \
183 static const TCCodecID  PREFIX ## _codecs_in = { TC_CODEC_ERROR }; \
184 static const TCFormatID PREFIX ## _formats_out[] = { TC_FORMAT_ERROR }
185 
186 /*
187  * plugin entry point prototype
188  */
189 const TCModuleClass *tc_plugin_setup(void);
190 
191 #define TC_MODULE_ENTRY_POINT(MODNAME) \
192     extern const TCModuleClass *tc_plugin_setup(void) \
193     { \
194         return &( MODNAME ## _class); \
195     }
196 
197 
198 /* TODO: unify in a proper way OLDINTERFACE and OLDINTERFACE_M */
199 #define TC_FILTER_OLDINTERFACE(name) \
200     /* Old-fashioned module interface. */ \
201     static TCModuleInstance mod; \
202     \
203     int tc_filter(frame_list_t *frame, char *options) \
204     { \
205         if (frame->tag & TC_FILTER_INIT) { \
206             if (name ## _init(&mod, TC_MODULE_FEATURE_FILTER) < 0) { \
207                 return TC_ERROR; \
208             } \
209             return name ## _configure(&mod, options, tc_get_vob()); \
210         \
211         } else if (frame->tag & TC_FILTER_GET_CONFIG) { \
212             return name ## _get_config(&mod, options); \
213         \
214         } else if (frame->tag & TC_FILTER_CLOSE) { \
215             if (name ## _stop(&mod) < 0) { \
216                 return TC_ERROR; \
217             } \
218             return name ## _fini(&mod); \
219         } \
220         \
221         return name ## _process(&mod, frame); \
222     }
223 
224 
225 
226 #define TC_FILTER_OLDINTERFACE_INSTANCES	128
227 
228 /* FIXME:
229  * this uses the filter ID as an index--the ID can grow
230  * arbitrarily large, so this needs to be fixed
231  */
232 #define TC_FILTER_OLDINTERFACE_M(name) \
233     /* Old-fashioned module interface. */ \
234     static TCModuleInstance mods[TC_FILTER_OLDINTERFACE_INSTANCES]; \
235     \
236     int tc_filter(frame_list_t *frame, char *options) \
237     { \
238 	TCModuleInstance *mod = &mods[frame->filter_id]; \
239 	\
240         if (frame->tag & TC_FILTER_INIT) { \
241             tc_log_info(MOD_NAME, "instance #%i", frame->filter_id); \
242             if (name ## _init(mod, TC_MODULE_FEATURE_FILTER) < 0) { \
243                 return TC_ERROR; \
244             } \
245             return name ## _configure(mod, options, tc_get_vob()); \
246         \
247         } else if (frame->tag & TC_FILTER_GET_CONFIG) { \
248             return name ## _get_config(mod, options); \
249         \
250         } else if (frame->tag & TC_FILTER_CLOSE) { \
251             if (name ## _stop(mod) < 0) { \
252                 return TC_ERROR; \
253             } \
254             return name ## _fini(mod); \
255         } \
256         \
257         return name ## _process(mod, frame); \
258     }
259 
260 
261 
262 #endif /* TCMODULE_PLUGIN_H */
263