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