1 /*
2  * Copyright (C) 2000-2018 the xine project
3  * May 2003 - Miguel Freitas
4  * This plugin was sponsored by 1Control
5  *
6  * This file is part of xine, a free video player.
7  *
8  * xine is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * xine is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
21  */
22 
23 /*
24  * demuxer for slave "protocol"
25  * master xine must be started with XINE_PARAM_BROADCASTER_PORT set, that is,
26  * 'xine --broadcast-port <port_number>'
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <string.h>
38 
39 #define LOG_MODULE "demux_slave"
40 #define LOG_VERBOSE
41 /*
42 #define LOG
43 */
44 
45 #include <xine/xine_internal.h>
46 #include <xine/xineutils.h>
47 #include <xine/compat.h>
48 #include <xine/demux.h>
49 
50 #define SCRATCH_SIZE        1024
51 #define CHECK_VPTS_INTERVAL 2*90000
52 #define NETWORK_PREBUFFER   90000
53 
54 typedef struct {
55   demux_plugin_t      demux_plugin;
56 
57   xine_stream_t       *stream;
58   fifo_buffer_t       *video_fifo;
59   fifo_buffer_t       *audio_fifo;
60   input_plugin_t      *input;
61   int                  status;
62 
63   int64_t              last_vpts;
64   int                  send_newpts;
65 
66                         /* additional decoder flags and other dec-spec. stuff */
67   uint32_t             decoder_info[BUF_NUM_DEC_INFO];
68                         /* pointers to dec-spec. stuff */
69   void                 *decoder_info_ptr[BUF_NUM_DEC_INFO];
70   xine_list_t          *dec_infos;   /* dec-spec. stuff */
71 
72   uint8_t              scratch[SCRATCH_SIZE+1];
73   int                  scratch_used;
74 } demux_slave_t ;
75 
76 
77 #define MAX_COMMAND_SIZE 20
78 
demux_slave_next(demux_slave_t * this)79 static int demux_slave_next (demux_slave_t *this) {
80   buf_element_t *buf;
81   int n, i;
82   char fifo_name[11];
83   uint8_t *p, *s;
84   int64_t curvpts;
85 
86   /* fill the scratch buffer */
87   n = this->input->read(this->input, &this->scratch[this->scratch_used],
88                         SCRATCH_SIZE - this->scratch_used);
89   if (n <= 0) {
90     lprintf("connection closed\n");
91     this->status = DEMUX_FINISHED;
92     return 0;
93   }
94 
95   this->scratch_used += n;
96   this->scratch[this->scratch_used] = '\0';
97 
98   p = strchr(this->scratch,'\n');
99   s = strchr(this->scratch,' ');
100 
101   if( !s || s > p )
102     s = p;
103 
104   if( !p || !s || (s-this->scratch+1) > MAX_COMMAND_SIZE ) {
105     lprintf("protocol error\n");
106     this->status = DEMUX_FINISHED;
107     return 0;
108   }
109 
110   *s++ = '\0';
111   p++;
112 
113   if( !strcmp(this->scratch,"buffer") ) {
114     int32_t    size ;     /* size of _content_                                     */
115     uint32_t   type;
116     int64_t    pts;       /* presentation time stamp, used for a/v sync            */
117     int64_t    disc_off;  /* discontinuity offset                                  */
118     uint32_t   decoder_flags; /* stuff like keyframe, is_header ... see below      */
119 
120     if( sscanf(s,"fifo=%10s size=%"  SCNd32 " type=%" SCNu32 " pts=%" SCNd64 " disc=%" SCNd64 " flags=%" SCNu32,
121                fifo_name, &size, &type, &pts, &disc_off, &decoder_flags) != 6 ) {
122       lprintf("'buffer' command error\n");
123       this->status = DEMUX_FINISHED;
124       return 0;
125     }
126 
127     if( type == BUF_CONTROL_NEWPTS ) {
128       this->send_newpts = 0;
129       this->last_vpts = 0;
130     }
131 
132     /* if we join an already existing broadcaster we must take care
133      * of the initial pts.
134      */
135     if( pts && this->send_newpts ) {
136       _x_demux_control_newpts( this->stream, pts, 0 );
137       this->send_newpts = 0;
138     }
139 
140     /* check if we are not late on playback.
141      * that might happen if user hits "pause" on the master, for example.
142      */
143     if( pts &&
144         (curvpts = this->stream->xine->clock->get_current_time(this->stream->xine->clock)) >
145         (this->last_vpts + CHECK_VPTS_INTERVAL) ) {
146       if( this->last_vpts &&
147           pts - (NETWORK_PREBUFFER/2) +
148           this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET) <
149           curvpts ) {
150         xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "we are running late, forcing newpts.\n");
151         _x_demux_control_newpts( this->stream, pts - NETWORK_PREBUFFER, 0 );
152       }
153       this->last_vpts = curvpts;
154     }
155 
156 
157     if( !strcmp(fifo_name,"video") || !this->audio_fifo )
158       buf = this->video_fifo->buffer_pool_alloc(this->video_fifo);
159     else
160       buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo);
161 
162     /* copy data to buf, either from stratch or network */
163     n = this->scratch_used - (p-this->scratch);
164     if( n > size )
165       n = size;
166     if( n )
167       memcpy(buf->content, p, n);
168     if( n < size ) {
169       if (this->input->read(this->input, &buf->content[n], size-n) != (size-n)) {
170         buf->free_buffer(buf);
171         this->status = DEMUX_FINISHED;
172         return 0;
173       }
174     }
175 
176     p += n;
177     n = this->scratch_used - (p-this->scratch);
178     if( n )
179       memmove(this->scratch, p, n);
180     this->scratch_used = n;
181 
182     /* populate our buf */
183     buf->size = size;
184     buf->type = type;
185     buf->pts = pts;
186     buf->disc_off = disc_off;
187     buf->decoder_flags = decoder_flags;
188 
189     /* set decoder info */
190     memcpy(buf->decoder_info, this->decoder_info, sizeof(this->decoder_info));
191     memcpy(buf->decoder_info_ptr, this->decoder_info_ptr, sizeof(this->decoder_info));
192     memset(this->decoder_info, 0, sizeof(this->decoder_info));
193     memset(this->decoder_info_ptr, 0, sizeof(this->decoder_info_ptr));
194 
195     if( !strcmp(fifo_name,"video") )
196       this->video_fifo->put(this->video_fifo, buf);
197     else if (this->audio_fifo)
198       this->audio_fifo->put(this->audio_fifo, buf);
199     else
200       buf->free_buffer(buf);
201 
202   } else if( !strcmp(this->scratch,"decoder_info") ) {
203 
204     uint32_t decoder_info;
205     int has_data;
206     int size;
207 
208     if( sscanf(s,"index=%d decoder_info=%u has_data=%d",
209                &i, &decoder_info, &has_data) != 3 ||
210                i < 0 || i >= BUF_NUM_DEC_INFO) {
211       lprintf("'decoder_info' command error\n");
212       this->status = DEMUX_FINISHED;
213       return 0;
214     }
215 
216     this->decoder_info[i] = decoder_info;
217 
218     size = (has_data) ? decoder_info : 0;
219 
220     if( size ) {
221       this->decoder_info_ptr[i] = malloc(size);
222       xine_list_push_back(this->dec_infos, this->decoder_info_ptr[i]);
223     }
224 
225     n = this->scratch_used - (p-this->scratch);
226     if( n > size )
227       n = size;
228     if( n )
229       memcpy(this->decoder_info_ptr[i], p, n);
230     if( n < size ) {
231       if (this->input->read(this->input, (char *)this->decoder_info_ptr[i]+n, size-n) != (size-n)) {
232         this->status = DEMUX_FINISHED;
233         return 0;
234       }
235     }
236 
237     p += n;
238     n = this->scratch_used - (p-this->scratch);
239     if( n )
240       memmove(this->scratch, p, n);
241     this->scratch_used = n;
242 
243 
244   } else if( !strcmp(this->scratch,"flush_engine") ) {
245 
246     _x_demux_flush_engine( this->stream );
247     n = this->scratch_used - (p-this->scratch);
248     if( n )
249       memmove(this->scratch, p, n);
250     this->scratch_used = n;
251 
252   } else {
253     lprintf("unknown command '%s'\n", this->scratch);
254     n = this->scratch_used - (p-this->scratch);
255     if( n )
256       memmove(this->scratch, p, n);
257     this->scratch_used = n;
258   }
259 
260   return 1;
261 }
262 
demux_slave_send_chunk(demux_plugin_t * this_gen)263 static int demux_slave_send_chunk (demux_plugin_t *this_gen) {
264   demux_slave_t *this = (demux_slave_t *) this_gen;
265 
266   demux_slave_next(this);
267 
268   return this->status;
269 }
270 
demux_slave_get_status(demux_plugin_t * this_gen)271 static int demux_slave_get_status (demux_plugin_t *this_gen) {
272   demux_slave_t *this = (demux_slave_t *) this_gen;
273 
274   return this->status;
275 }
276 
277 
demux_slave_send_headers(demux_plugin_t * this_gen)278 static void demux_slave_send_headers (demux_plugin_t *this_gen) {
279   demux_slave_t *this = (demux_slave_t *) this_gen;
280 
281   this->video_fifo  = this->stream->video_fifo;
282   this->audio_fifo  = this->stream->audio_fifo;
283 
284   _x_demux_control_start(this->stream);
285 
286   this->status = DEMUX_OK;
287 
288   _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1);
289   _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1);
290 
291   this->last_vpts = 0;
292   this->send_newpts = 1;
293 }
294 
demux_slave_seek(demux_plugin_t * this_gen,off_t start_pos,int start_time,int playing)295 static int demux_slave_seek (demux_plugin_t *this_gen, off_t start_pos, int start_time, int playing) {
296   demux_slave_t *this = (demux_slave_t *) this_gen;
297 
298   (void)this_gen;
299   (void)start_pos;
300   (void)start_time;
301   (void)playing;
302   return this->status;
303 }
304 
demux_slave_dispose(demux_plugin_t * this_gen)305 static void demux_slave_dispose (demux_plugin_t *this_gen) {
306   demux_slave_t *this = (demux_slave_t *) this_gen;
307   void *data;
308   xine_list_iterator_t ite;
309 
310   /* free all decoder information */
311   ite = NULL;
312   while ((data = xine_list_next_value (this->dec_infos, &ite)))
313     free(data);
314   xine_list_delete(this->dec_infos);
315 
316   free (this);
317 }
318 
demux_slave_get_stream_length(demux_plugin_t * this_gen)319 static int demux_slave_get_stream_length(demux_plugin_t *this_gen) {
320   (void)this_gen;
321   return 0 ; /*FIXME: implement */
322 }
323 
demux_slave_get_capabilities(demux_plugin_t * this_gen)324 static uint32_t demux_slave_get_capabilities(demux_plugin_t *this_gen) {
325   (void)this_gen;
326   return DEMUX_CAP_NOCAP;
327 }
328 
demux_slave_get_optional_data(demux_plugin_t * this_gen,void * data,int data_type)329 static int demux_slave_get_optional_data(demux_plugin_t *this_gen,
330 					void *data, int data_type) {
331   (void)this_gen;
332   (void)data;
333   (void)data_type;
334   return DEMUX_OPTIONAL_UNSUPPORTED;
335 }
336 
337 
open_plugin(demux_class_t * class_gen,xine_stream_t * stream,input_plugin_t * input)338 static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream,
339                                     input_plugin_t *input) {
340 
341   static const char slave_id_str[] = "master xine v1\n";
342   const size_t      slave_id_str_len = strlen(slave_id_str);
343   demux_slave_t *this;
344   char           scratch[sizeof(slave_id_str)];
345 
346   switch (stream->content_detection_method) {
347 
348   case METHOD_BY_CONTENT:
349     if (_x_demux_read_header (input, scratch, slave_id_str_len) != (int)slave_id_str_len)
350       return NULL;
351     if (memcmp(scratch, slave_id_str, slave_id_str_len))
352       return NULL;
353     break;
354 
355   case METHOD_BY_MRL:
356   case METHOD_EXPLICIT:
357     break;
358 
359   default:
360     return NULL;
361   }
362 
363   if (input->seek (input, slave_id_str_len, SEEK_SET) != (int)slave_id_str_len)
364     return NULL;
365 
366   this = calloc(1, sizeof(demux_slave_t));
367   if (!this)
368     return NULL;
369 
370   this->stream = stream;
371   this->input  = input;
372   this->dec_infos = xine_list_new();
373 
374   this->demux_plugin.send_headers      = demux_slave_send_headers;
375   this->demux_plugin.send_chunk        = demux_slave_send_chunk;
376   this->demux_plugin.seek              = demux_slave_seek;
377   this->demux_plugin.dispose           = demux_slave_dispose;
378   this->demux_plugin.get_status        = demux_slave_get_status;
379   this->demux_plugin.get_stream_length = demux_slave_get_stream_length;
380   this->demux_plugin.get_capabilities  = demux_slave_get_capabilities;
381   this->demux_plugin.get_optional_data = demux_slave_get_optional_data;
382   this->demux_plugin.demux_class       = class_gen;
383 
384   this->status = DEMUX_FINISHED;
385 
386   this->scratch_used = 0;
387 
388   memset(this->decoder_info, 0, sizeof(this->decoder_info));
389   memset(this->decoder_info_ptr, 0, sizeof(this->decoder_info_ptr));
390 
391   return &this->demux_plugin;
392 }
393 
init_plugin(xine_t * xine,const void * data)394 static void *init_plugin (xine_t *xine, const void *data) {
395 
396   (void)xine;
397   (void)data;
398 
399   static const demux_class_t demux_slave_class = {
400     .open_plugin     = open_plugin,
401     .description     = "",
402     .identifier      = "slave",
403     .mimetypes       = NULL,
404     .extensions      = "slave://",
405     .dispose         = NULL,
406   };
407 
408   return (void *)&demux_slave_class;
409 }
410 
411 /*
412  * exported plugin catalog entry
413  */
414 static const demuxer_info_t demux_info_slave = {
415   .priority = 10,
416 };
417 
418 const plugin_info_t xine_plugin_info[] EXPORTED = {
419   /* type, API, "name", version, special_info, init_function */
420   { PLUGIN_DEMUX, 27, "slave", XINE_VERSION_CODE, &demux_info_slave, init_plugin },
421   { PLUGIN_NONE, 0, NULL, 0, NULL, NULL }
422 };
423