a192d48c136f7db6a69cebbcb3784e8c5eb813d5
[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
51 struct test_es_out_t
52 {
53     struct es_out_t out;
54     struct es_out_id_t *ids;
55 };
56
57 struct es_out_id_t
58 {
59     struct es_out_id_t *next;
60 };
61
62 static es_out_id_t *EsOutAdd(es_out_t *out, const es_format_t *fmt)
63 {
64     struct test_es_out_t *ctx = (struct test_es_out_t *) out;
65
66     if (fmt->i_group < 0)
67         return NULL;
68
69     es_out_id_t *id = malloc(sizeof (*id));
70     if (unlikely(id == NULL))
71         return NULL;
72
73     id->next = ctx->ids;
74     ctx->ids = id;
75
76     debug("[%p] Added   ES\n", (void *)id);
77     return id;
78 }
79
80 static void EsOutCheckId(es_out_t *out, es_out_id_t *id)
81 {
82     struct test_es_out_t *ctx = (struct test_es_out_t *) out;
83
84     for (es_out_id_t *ids = ctx->ids; ids != NULL; ids = ids->next)
85         if (ids == id)
86             return;
87
88     abort();
89 }
90
91 static int EsOutSend(es_out_t *out, es_out_id_t *id, block_t *block)
92 {
93     //debug("[%p] Sent    ES: %zu\n", (void *)idd, block->i_buffer);
94     EsOutCheckId(out, id);
95     block_Release(block);
96     return VLC_SUCCESS;
97 }
98
99 static void EsOutDelete(es_out_t *out, es_out_id_t *id)
100 {
101     struct test_es_out_t *ctx = (struct test_es_out_t *) out;
102     es_out_id_t **pp = &ctx->ids;
103
104     while (*pp != id)
105     {
106         if (*pp == NULL)
107             abort();
108         pp = &((*pp)->next);
109     }
110
111     debug("[%p] Deleted ES\n", (void *)id);
112     *pp = id->next;
113     free(id);
114 }
115
116 static int EsOutControl(es_out_t *out, int query, va_list args)
117 {
118     switch (query)
119     {
120         case ES_OUT_SET_ES:
121             break;
122         case ES_OUT_RESTART_ES:
123             abort();
124         case ES_OUT_SET_ES_DEFAULT:
125         case ES_OUT_SET_ES_STATE:
126             break;
127         case ES_OUT_GET_ES_STATE:
128             EsOutCheckId(out, va_arg(args, es_out_id_t *));
129             *va_arg(args, bool *) = true;
130             break;
131         case ES_OUT_SET_ES_CAT_POLICY:
132             break;
133         case ES_OUT_SET_GROUP:
134             abort();
135         case ES_OUT_SET_PCR:
136         case ES_OUT_SET_GROUP_PCR:
137         case ES_OUT_RESET_PCR:
138         case ES_OUT_SET_ES_FMT:
139         case ES_OUT_SET_NEXT_DISPLAY_TIME:
140         case ES_OUT_SET_GROUP_META:
141         case ES_OUT_SET_GROUP_EPG:
142         case ES_OUT_DEL_GROUP:
143         case ES_OUT_SET_ES_SCRAMBLED_STATE:
144             break;
145         case ES_OUT_GET_EMPTY:
146             *va_arg(args, bool *) = true;
147             break;
148         case ES_OUT_SET_META:
149             break;
150         case ES_OUT_GET_PCR_SYSTEM:
151         case ES_OUT_MODIFY_PCR_SYSTEM:
152             abort();
153         default:
154             return VLC_EGENERIC;
155     }
156     return VLC_SUCCESS;
157 }
158
159 static void EsOutDestroy(es_out_t *out)
160 {
161     struct test_es_out_t *ctx = (struct test_es_out_t *)out;
162     es_out_id_t *id;
163
164     while ((id = ctx->ids) != NULL)
165     {
166         ctx->ids = id->next;
167         free(id);
168     }
169     free(ctx);
170 }
171
172 static es_out_t *test_es_out_create(vlc_object_t *parent)
173 {
174     struct test_es_out_t *ctx = malloc(sizeof (*ctx));
175     if (ctx == NULL)
176     {
177         fprintf(stderr, "Error: cannot create ES output.\n");
178         return NULL;
179     }
180
181     ctx->ids = NULL;
182
183     es_out_t *out = &ctx->out;
184     out->pf_add = EsOutAdd;
185     out->pf_send = EsOutSend;
186     out->pf_del = EsOutDelete;
187     out->pf_control = EsOutControl;
188     out->pf_destroy = EsOutDestroy;
189     out->p_sys = (void *)parent;
190
191     return out;
192 }
193
194 static unsigned demux_test_and_clear_flags(demux_t *demux, unsigned flags)
195 {
196     unsigned update;
197     if (demux_Control(demux, DEMUX_TEST_AND_CLEAR_FLAGS, &update) == VLC_SUCCESS)
198         return update;
199     unsigned ret = demux->info.i_update & flags;
200     demux->info.i_update &= ~flags;
201     return ret;
202 }
203
204 static void demux_get_title_list(demux_t *demux)
205 {
206     int title;
207     int title_offset;
208     int seekpoint_offset;
209     input_title_t **title_list;
210
211     if (demux_Control(demux, DEMUX_GET_TITLE_INFO, &title_list, &title,
212                       &title_offset, &seekpoint_offset) == VLC_SUCCESS)
213     {
214         for (int i = 0; i < title; i++)
215             vlc_input_title_Delete(title_list[i]);
216     }
217 }
218
219 static void demux_get_meta(demux_t *demux)
220 {
221     vlc_meta_t *p_meta = vlc_meta_New();
222     if (unlikely(p_meta == NULL) )
223         return;
224
225     input_attachment_t **attachment;
226     int i_attachment;
227
228     demux_Control(demux, DEMUX_GET_META, p_meta);
229     demux_Control(demux, DEMUX_GET_ATTACHMENTS, &attachment, &i_attachment);
230
231     vlc_meta_Delete(p_meta);
232 }
233
234 static int demux_process_stream(const struct vlc_run_args *args, stream_t *s)
235 {
236     const char *name = args->name;
237     if (name == NULL)
238         name = "any";
239
240     if (s == NULL)
241         return -1;
242
243     es_out_t *out = test_es_out_create(VLC_OBJECT(s));
244     if (out == NULL)
245         return -1;
246
247     demux_t *demux = demux_New(VLC_OBJECT(s), name, "", s, out);
248     if (demux == NULL)
249     {
250         es_out_Delete(out);
251         vlc_stream_Delete(s);
252         debug("Error: cannot create demultiplexer: %s\n", name);
253         return -1;
254     }
255
256     uintmax_t i = 0;
257     int val;
258
259     while ((val = demux_Demux(demux)) == VLC_DEMUXER_SUCCESS)
260     {
261         if (args->test_demux_controls)
262         {
263             if (demux_test_and_clear_flags(demux, INPUT_UPDATE_TITLE_LIST))
264                 demux_get_title_list(demux);
265
266             if (demux_test_and_clear_flags(demux, INPUT_UPDATE_META))
267                 demux_get_meta(demux);
268
269             int seekpoint = 0;
270             double position = 0.0;
271             mtime_t time = 0;
272             mtime_t length = 0;
273
274             /* Call controls for increased code coverage */
275             demux_Control(demux, DEMUX_GET_SEEKPOINT, &seekpoint);
276             demux_Control(demux, DEMUX_GET_POSITION, &position);
277             demux_Control(demux, DEMUX_GET_TIME, &time);
278             demux_Control(demux, DEMUX_GET_LENGTH, &length);
279         }
280         i++;
281     }
282
283     demux_Delete(demux);
284     es_out_Delete(out);
285
286     debug("Completed with %ju iteration(s).\n", i);
287
288     return val == VLC_DEMUXER_EOF ? 0 : -1;
289 }
290
291 int vlc_demux_process_url(const struct vlc_run_args *args, const char *url)
292 {
293     libvlc_instance_t *vlc = libvlc_create(args);
294     if (vlc == NULL)
295         return -1;
296
297     stream_t *s = vlc_access_NewMRL(VLC_OBJECT(vlc->p_libvlc_int), url);
298     if (s == NULL)
299         fprintf(stderr, "Error: cannot create input stream: %s\n", url);
300
301     int ret = demux_process_stream(args, s);
302     libvlc_release(vlc);
303     return ret;
304 }
305
306 int vlc_demux_process_path(const struct vlc_run_args *args, const char *path)
307 {
308     char *url = vlc_path2uri(path, NULL);
309     if (url == NULL)
310     {
311         fprintf(stderr, "Error: cannot convert path to URL: %s\n", path);
312         return -1;
313     }
314
315     int ret = vlc_demux_process_url(args, url);
316     free(url);
317     return ret;
318 }
319
320 int vlc_demux_process_memory(const struct vlc_run_args *args,
321                              const unsigned char *buf, size_t length)
322 {
323     libvlc_instance_t *vlc = libvlc_create(args);
324     if (vlc == NULL)
325         return -1;
326
327     stream_t *s = vlc_stream_MemoryNew(VLC_OBJECT(vlc->p_libvlc_int),
328                                        (void *)buf, length, true);
329     if (s == NULL)
330         fprintf(stderr, "Error: cannot create input stream\n");
331
332     int ret = demux_process_stream(args, s);
333     libvlc_release(vlc);
334     return ret;
335 }
336
337 #ifdef HAVE_STATIC_MODULES
338 # include <vlc_plugin.h>
339
340 typedef int (*vlc_plugin_cb)(int (*)(void *, void *, int, ...), void *);
341 extern vlc_plugin_cb vlc_static_modules[];
342
343 #define PLUGINS(f) \
344     f(xml) \
345     f(console) \
346     f(filesystem) \
347     f(xml) \
348     f(aiff) \
349     f(asf) \
350     f(au) \
351     f(avi) \
352     f(caf) \
353     f(diracsys) \
354     f(es) \
355     f(flacsys) \
356     f(h26x) \
357     f(mjpeg) \
358     f(mkv) \
359     f(mp4) \
360     f(nsc) \
361     f(nsv) \
362     f(ps) \
363     f(pva) \
364     f(sap) \
365     f(smf) \
366     f(subtitle) \
367     PLUGIN_TS(f) \
368     f(tta) \
369     f(ttml) \
370     f(ty) \
371     f(voc) \
372     f(wav) \
373     f(webvtt) \
374     f(xa) \
375     f(a52) \
376     f(dirac) \
377     f(dts) \
378     f(flac) \
379     f(h264) \
380     f(hevc) \
381     f(mlp) \
382     f(mpeg4audio) \
383     f(mpeg4video) \
384     f(mpegaudio) \
385     f(mpegvideo) \
386     f(vc1)
387 #ifdef HAVE_DVBPSI
388 # define PLUGIN_TS(f) f(ts)
389 #else
390 # define PLUGIN_TS(f)
391 #endif
392
393 #define DECL_PLUGIN(p) \
394     int vlc_entry__##p(int (*)(void *, void *, int, ...), void *);
395
396 #define FUNC_PLUGIN(p) \
397     vlc_entry__##p,
398
399 PLUGINS(DECL_PLUGIN)
400
401 __attribute__((visibility("default")))
402 vlc_plugin_cb vlc_static_modules[] = { PLUGINS(FUNC_PLUGIN) NULL };
403 #endif /* HAVE_STATIC_MODULES */