1 /*****************************************************************************
2  * demux_chained.c
3  *****************************************************************************
4  * Copyright (C) 1999-2016 VLC authors and VideoLAN
5  *
6  * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
7  *          Rémi Denis-Courmont
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23 
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 
28 #include <limits.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <vlc_common.h>
32 #include <vlc_demux.h>
33 #include "demux.h"
34 
35 struct vlc_demux_chained_t
36 {
37     stream_t *fifo;
38 
39     vlc_thread_t thread;
40     vlc_mutex_t  lock;
41 
42     struct
43     {
44         double  position;
45         int64_t length;
46         int64_t time;
47     } stats;
48 
49     es_out_t *out;
50     char name[];
51 };
52 
vlc_demux_chained_Thread(void * data)53 static void *vlc_demux_chained_Thread(void *data)
54 {
55     vlc_demux_chained_t *dc = data;
56     demux_t *demux = demux_NewAdvanced(dc->fifo, NULL, "", dc->name, "",
57                                        dc->fifo, dc->out, false);
58     if (demux == NULL)
59     {
60         vlc_stream_Delete(dc->fifo);
61         return NULL;
62     }
63 
64     /* Stream FIFO cannot apply DVB filters.
65      * Get all programs and let the E/S output sort them out. */
66     demux_Control(demux, DEMUX_SET_GROUP, -1, NULL);
67 
68     /* Main loop */
69     mtime_t next_update = 0;
70 
71     do
72         if (demux_TestAndClearFlags(demux, UINT_MAX) || mdate() >= next_update)
73         {
74             double newpos;
75             int64_t newlen, newtime;
76 
77             if (demux_Control(demux, DEMUX_GET_POSITION, &newpos))
78                 newpos = 0.;
79             if (demux_Control(demux, DEMUX_GET_LENGTH, &newlen))
80                 newlen = 0;
81             if (demux_Control(demux, DEMUX_GET_TIME, &newtime))
82                 newtime = 0;
83 
84             vlc_mutex_lock(&dc->lock);
85             dc->stats.position = newpos;
86             dc->stats.length = newlen;
87             dc->stats.time = newtime;
88             vlc_mutex_unlock(&dc->lock);
89 
90             next_update = mdate() + (CLOCK_FREQ / 4);
91         }
92     while (demux_Demux(demux) > 0);
93 
94     demux_Delete(demux);
95     return NULL;
96 }
97 
vlc_demux_chained_New(vlc_object_t * parent,const char * name,es_out_t * out)98 vlc_demux_chained_t *vlc_demux_chained_New(vlc_object_t *parent,
99                                            const char *name, es_out_t *out)
100 {
101     vlc_demux_chained_t *dc = malloc(sizeof (*dc) + strlen(name) + 1);
102     if (unlikely(dc == NULL))
103         return NULL;
104 
105     dc->fifo = vlc_stream_fifo_New(parent);
106     if (dc->fifo == NULL)
107     {
108         free(dc);
109         return NULL;
110     }
111 
112     dc->stats.position = 0.;
113     dc->stats.length = 0;
114     dc->stats.time = 0;
115     dc->out = out;
116     strcpy(dc->name, name);
117 
118     vlc_mutex_init(&dc->lock);
119 
120     if (vlc_clone(&dc->thread, vlc_demux_chained_Thread, dc,
121                   VLC_THREAD_PRIORITY_INPUT))
122     {
123         vlc_stream_Delete(dc->fifo);
124         vlc_stream_fifo_Close(dc->fifo);
125         vlc_mutex_destroy(&dc->lock);
126         free(dc);
127         dc = NULL;
128     }
129     return dc;
130 }
131 
vlc_demux_chained_Send(vlc_demux_chained_t * dc,block_t * block)132 void vlc_demux_chained_Send(vlc_demux_chained_t *dc, block_t *block)
133 {
134     vlc_stream_fifo_Queue(dc->fifo, block);
135 }
136 
vlc_demux_chained_ControlVa(vlc_demux_chained_t * dc,int query,va_list ap)137 int vlc_demux_chained_ControlVa(vlc_demux_chained_t *dc, int query, va_list ap)
138 {
139     switch (query)
140     {
141         case DEMUX_GET_POSITION:
142             vlc_mutex_lock(&dc->lock);
143             *va_arg(ap, double *) = dc->stats.position;
144             vlc_mutex_unlock(&dc->lock);
145             break;
146         case DEMUX_GET_LENGTH:
147             vlc_mutex_lock(&dc->lock);
148             *va_arg(ap, int64_t *) = dc->stats.length;
149             vlc_mutex_unlock(&dc->lock);
150             break;
151         case DEMUX_GET_TIME:
152             vlc_mutex_lock(&dc->lock);
153             *va_arg(ap, int64_t *) = dc->stats.time;
154             vlc_mutex_unlock(&dc->lock);
155             break;
156         default:
157             return VLC_EGENERIC;
158     }
159     return VLC_SUCCESS;
160 }
161 
vlc_demux_chained_Delete(vlc_demux_chained_t * dc)162 void vlc_demux_chained_Delete(vlc_demux_chained_t *dc)
163 {
164     vlc_stream_fifo_Close(dc->fifo);
165     vlc_join(dc->thread, NULL);
166     vlc_mutex_destroy(&dc->lock);
167     free(dc);
168 }
169