test: input: test decoder from demux
[vlc.git] / test / src / input / demux-run.c
1 /**
2  * @file demux-run.c
3  */
4 /*****************************************************************************
5  * Copyright © 2016 Rémi Denis-Courmont
6  *
7  * This program 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  * Rémi Denis-Courmont reserves the right to redistribute this file under
13  * the terms of the GNU Lesser General Public License as published by the
14  * the Free Software Foundation; either version 2.1 or the License, or
15  * (at his option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <limits.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36
37 #include <vlc_common.h>
38 #include <vlc_access.h>
39 #include <vlc_block.h>
40 #include <vlc_demux.h>
41 #include <vlc_input.h>
42 #include <vlc_meta.h>
43 #include <vlc_es_out.h>
44 #include <vlc_url.h>
45 #include "../lib/libvlc_internal.h"
46
47 #include <vlc/vlc.h>
48
49 #include "demux-run.h"
50 #include "decoder.h"
51
52 struct test_es_out_t
53 {
54     struct es_out_t out;
55     struct es_out_id_t *ids;
56 };
57
58 struct es_out_id_t
59 {
60     struct es_out_id_t *next;
61 #ifdef HAVE_DECODERS
62     decoder_t *decoder;
63 #endif
64 };
65
66 static es_out_id_t *EsOutAdd(es_out_t *out, const es_format_t *fmt)
67 {
68     struct test_es_out_t *ctx = (struct test_es_out_t *) out;
69
70     if (fmt->i_group < 0)
71         return NULL;
72
73     es_out_id_t *id = malloc(sizeof (*id));
74     if (unlikely(id == NULL))
75         return NULL;
76
77     id->next = ctx->ids;
78     ctx->ids = id;
79 #ifdef HAVE_DECODERS
80     id->decoder = test_decoder_create((void *)out->p_sys, fmt);
81 #endif
82
83     debug("[%p] Added   ES\n", (void *)id);
84     return id;
85 }
86
87 static void EsOutCheckId(es_out_t *out, es_out_id_t *id)
88 {
89     struct test_es_out_t *ctx = (struct test_es_out_t *) out;
90
91     for (es_out_id_t *ids = ctx->ids; ids != NULL; ids = ids->next)
92         if (ids == id)
93             return;
94
95     abort();
96 }
97
98 static int EsOutSend(es_out_t *out, es_out_id_t *id, block_t *block)
99 {
100     //debug("[%p] Sent    ES: %zu\n", (void *)idd, block->i_buffer);
101     EsOutCheckId(out, id);
102 #ifdef HAVE_DECODERS
103     if (id->decoder)
104         test_decoder_process(id->decoder, block);
105     else
106 #endif
107         block_Release(block);
108     return VLC_SUCCESS;
109 }
110
111 static void IdDelete(es_out_id_t *id)
112 {
113 #ifdef HAVE_DECODERS
114     if (id->decoder)
115     {
116         /* Drain */
117         test_decoder_process(id->decoder, NULL);
118         test_decoder_destroy(id->decoder);
119     }
120 #endif
121     free(id);
122 }
123
124 static void EsOutDelete(es_out_t *out, es_out_id_t *id)
125 {
126     struct test_es_out_t *ctx = (struct test_es_out_t *) out;
127     es_out_id_t **pp = &ctx->ids;
128
129     while (*pp != id)
130     {
131         if (*pp == NULL)
132             abort();
133         pp = &((*pp)->next);
134     }
135
136     debug("[%p] Deleted ES\n", (void *)id);
137     *pp = id->next;
138     IdDelete(id);
139 }
140
141 static int EsOutControl(es_out_t *out, int query, va_list args)
142 {
143     switch (query)
144     {
145         case ES_OUT_SET_ES:
146             break;
147         case ES_OUT_RESTART_ES:
148             abort();
149         case ES_OUT_SET_ES_DEFAULT:
150         case ES_OUT_SET_ES_STATE:
151             break;
152         case ES_OUT_GET_ES_STATE:
153             EsOutCheckId(out, va_arg(args, es_out_id_t *));
154             *va_arg(args, bool *) = true;
155             break;
156         case ES_OUT_SET_ES_CAT_POLICY:
157             break;
158         case ES_OUT_SET_GROUP:
159             abort();
160         case ES_OUT_SET_PCR:
161         case ES_OUT_SET_GROUP_PCR:
162         case ES_OUT_RESET_PCR:
163         case ES_OUT_SET_ES_FMT:
164         case ES_OUT_SET_NEXT_DISPLAY_TIME:
165         case ES_OUT_SET_GROUP_META:
166         case ES_OUT_SET_GROUP_EPG:
167         case ES_OUT_DEL_GROUP:
168         case ES_OUT_SET_ES_SCRAMBLED_STATE:
169             break;
170         case ES_OUT_GET_EMPTY:
171             *va_arg(args, bool *) = true;
172             break;
173         case ES_OUT_SET_META:
174             break;
175         case ES_OUT_GET_PCR_SYSTEM:
176         case ES_OUT_MODIFY_PCR_SYSTEM:
177             abort();
178         default:
179             return VLC_EGENERIC;
180     }
181     return VLC_SUCCESS;
182 }
183
184 static void EsOutDestroy(es_out_t *out)
185 {
186     struct test_es_out_t *ctx = (struct test_es_out_t *)out;
187     es_out_id_t *id;
188
189     while ((id = ctx->ids) != NULL)
190     {
191         ctx->ids = id->next;
192         IdDelete(id);
193     }
194     free(ctx);
195 }
196
197 static es_out_t *test_es_out_create(vlc_object_t *parent)
198 {
199     struct test_es_out_t *ctx = malloc(sizeof (*ctx));
200     if (ctx == NULL)
201     {
202         fprintf(stderr, "Error: cannot create ES output.\n");
203         return NULL;
204     }
205
206     ctx->ids = NULL;
207
208     es_out_t *out = &ctx->out;
209     out->pf_add = EsOutAdd;
210     out->pf_send = EsOutSend;
211     out->pf_del = EsOutDelete;
212     out->pf_control = EsOutControl;
213     out->pf_destroy = EsOutDestroy;
214     out->p_sys = (void *)parent;
215
216     return out;
217 }
218
219 static unsigned demux_test_and_clear_flags(demux_t *demux, unsigned flags)
220 {
221     unsigned update;
222     if (demux_Control(demux, DEMUX_TEST_AND_CLEAR_FLAGS, &update) == VLC_SUCCESS)
223         return update;
224     unsigned ret = demux->info.i_update & flags;
225     demux->info.i_update &= ~flags;
226     return ret;
227 }
228
229 static void demux_get_title_list(demux_t *demux)
230 {
231     int title;
232     int title_offset;
233     int seekpoint_offset;
234     input_title_t **title_list;
235
236     if (demux_Control(demux, DEMUX_GET_TITLE_INFO, &title_list, &title,
237                       &title_offset, &seekpoint_offset) == VLC_SUCCESS)
238     {
239         for (int i = 0; i < title; i++)
240             vlc_input_title_Delete(title_list[i]);
241     }
242 }
243
244 static void demux_get_meta(demux_t *demux)
245 {
246     vlc_meta_t *p_meta = vlc_meta_New();
247     if (unlikely(p_meta == NULL) )
248         return;
249
250     input_attachment_t **attachment;
251     int i_attachment;
252
253     demux_Control(demux, DEMUX_GET_META, p_meta);
254     demux_Control(demux, DEMUX_GET_ATTACHMENTS, &attachment, &i_attachment);
255
256     vlc_meta_Delete(p_meta);
257 }
258
259 static int demux_process_stream(const struct vlc_run_args *args, stream_t *s)
260 {
261     const char *name = args->name;
262     if (name == NULL)
263         name = "any";
264
265     if (s == NULL)
266         return -1;
267
268     es_out_t *out = test_es_out_create(VLC_OBJECT(s));
269     if (out == NULL)
270         return -1;
271
272     demux_t *demux = demux_New(VLC_OBJECT(s), name, "", s, out);
273     if (demux == NULL)
274     {
275         es_out_Delete(out);
276         vlc_stream_Delete(s);
277         debug("Error: cannot create demultiplexer: %s\n", name);
278         return -1;
279     }
280
281     uintmax_t i = 0;
282     int val;
283
284     while ((val = demux_Demux(demux)) == VLC_DEMUXER_SUCCESS)
285     {
286         if (args->test_demux_controls)
287         {
288             if (demux_test_and_clear_flags(demux, INPUT_UPDATE_TITLE_LIST))
289                 demux_get_title_list(demux);
290
291             if (demux_test_and_clear_flags(demux, INPUT_UPDATE_META))
292                 demux_get_meta(demux);
293
294             int seekpoint = 0;
295             double position = 0.0;
296             mtime_t time = 0;
297             mtime_t length = 0;
298
299             /* Call controls for increased code coverage */
300             demux_Control(demux, DEMUX_GET_SEEKPOINT, &seekpoint);
301             demux_Control(demux, DEMUX_GET_POSITION, &position);
302             demux_Control(demux, DEMUX_GET_TIME, &time);
303             demux_Control(demux, DEMUX_GET_LENGTH, &length);
304         }
305         i++;
306     }
307
308     demux_Delete(demux);
309     es_out_Delete(out);
310
311     debug("Completed with %ju iteration(s).\n", i);
312
313     return val == VLC_DEMUXER_EOF ? 0 : -1;
314 }
315
316 int vlc_demux_process_url(const struct vlc_run_args *args, const char *url)
317 {
318     libvlc_instance_t *vlc = libvlc_create(args);
319     if (vlc == NULL)
320         return -1;
321
322     stream_t *s = vlc_access_NewMRL(VLC_OBJECT(vlc->p_libvlc_int), url);
323     if (s == NULL)
324         fprintf(stderr, "Error: cannot create input stream: %s\n", url);
325
326     int ret = demux_process_stream(args, s);
327     libvlc_release(vlc);
328     return ret;
329 }
330
331 int vlc_demux_process_path(const struct vlc_run_args *args, const char *path)
332 {
333     char *url = vlc_path2uri(path, NULL);
334     if (url == NULL)
335     {
336         fprintf(stderr, "Error: cannot convert path to URL: %s\n", path);
337         return -1;
338     }
339
340     int ret = vlc_demux_process_url(args, url);
341     free(url);
342     return ret;
343 }
344
345 int vlc_demux_process_memory(const struct vlc_run_args *args,
346                              const unsigned char *buf, size_t length)
347 {
348     libvlc_instance_t *vlc = libvlc_create(args);
349     if (vlc == NULL)
350         return -1;
351
352     stream_t *s = vlc_stream_MemoryNew(VLC_OBJECT(vlc->p_libvlc_int),
353                                        (void *)buf, length, true);
354     if (s == NULL)
355         fprintf(stderr, "Error: cannot create input stream\n");
356
357     int ret = demux_process_stream(args, s);
358     libvlc_release(vlc);
359     return ret;
360 }
361
362 #ifdef HAVE_STATIC_MODULES
363 # include <vlc_plugin.h>
364
365 typedef int (*vlc_plugin_cb)(int (*)(void *, void *, int, ...), void *);
366 extern vlc_plugin_cb vlc_static_modules[];
367
368 #ifdef HAVE_DECODERS
369 #define DECODER_PLUGINS(f) \
370     f(adpcm) \
371     f(aes3) \
372     f(araw) \
373     f(g711) \
374     f(lpcm) \
375     f(uleaddvaudio) \
376     f(rawvideo) \
377     f(cc) \
378     f(cvdsub) \
379     f(dvbsub) \
380     f(scte18) \
381     f(scte27) \
382     f(spudec) \
383     f(stl) \
384     f(subsdec) \
385     f(subsusf) \
386     f(svcdsub) \
387     f(textst) \
388     f(substx3g)
389 #else
390 #define DECODER_PLUGINS(f)
391 #endif
392
393 #define PLUGINS(f) \
394     f(xml) \
395     f(console) \
396     f(filesystem) \
397     f(xml) \
398     f(aiff) \
399     f(asf) \
400     f(au) \
401     f(avi) \
402     f(caf) \
403     f(diracsys) \
404     f(es) \
405     f(flacsys) \
406     f(h26x) \
407     f(mjpeg) \
408     f(mkv) \
409     f(mp4) \
410     f(nsc) \
411     f(nsv) \
412     f(ps) \
413     f(pva) \
414     f(sap) \
415     f(smf) \
416     f(subtitle) \
417     PLUGIN_TS(f) \
418     f(tta) \
419     f(ttml) \
420     f(ty) \
421     f(voc) \
422     f(wav) \
423     f(webvtt) \
424     f(xa) \
425     f(a52) \
426     f(dirac) \
427     f(dts) \
428     f(flac) \
429     f(h264) \
430     f(hevc) \
431     f(mlp) \
432     f(mpeg4audio) \
433     f(mpeg4video) \
434     f(mpegaudio) \
435     f(mpegvideo) \
436     f(vc1) \
437     DECODER_PLUGINS(f)
438
439 #ifdef HAVE_DVBPSI
440 # define PLUGIN_TS(f) f(ts)
441 #else
442 # define PLUGIN_TS(f)
443 #endif
444
445 #define DECL_PLUGIN(p) \
446     int vlc_entry__##p(int (*)(void *, void *, int, ...), void *);
447
448 #define FUNC_PLUGIN(p) \
449     vlc_entry__##p,
450
451 PLUGINS(DECL_PLUGIN)
452
453 __attribute__((visibility("default")))
454 vlc_plugin_cb vlc_static_modules[] = { PLUGINS(FUNC_PLUGIN) NULL };
455 #endif /* HAVE_STATIC_MODULES */