]> git.sesse.net Git - vlc/blob - modules/demux/livedotcom.cpp
include/vlc_es.h: defines es_format_t, audio_format_t, video_format_t.
[vlc] / modules / demux / livedotcom.cpp
1 /*****************************************************************************
2  * live.cpp : live.com support.
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: livedotcom.cpp,v 1.8 2003/11/20 22:10:55 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31
32 #include <codecs.h>                        /* BITMAPINFOHEADER, WAVEFORMATEX */
33 #include <iostream>
34
35 #if defined( WIN32 )
36 #   include <winsock2.h>
37 #endif
38
39 #include "BasicUsageEnvironment.hh"
40 #include "GroupsockHelper.hh"
41 #include "liveMedia.hh"
42
43 using namespace std;
44
45 /*****************************************************************************
46  * Module descriptor
47  *****************************************************************************/
48 static int  DemuxOpen ( vlc_object_t * );
49 static void DemuxClose( vlc_object_t * );
50
51 static int  AccessOpen ( vlc_object_t * );
52 static void AccessClose( vlc_object_t * );
53
54 #define CACHING_TEXT N_("Caching value in ms")
55 #define CACHING_LONGTEXT N_( \
56     "Allows you to modify the default caching value for rtsp streams. This " \
57     "value should be set in miliseconds units." )
58
59 vlc_module_begin();
60     set_description( _("live.com (RTSP/RTP/SDP) demuxer" ) );
61     set_capability( "demux", 50 );
62     set_callbacks( DemuxOpen, DemuxClose );
63     add_shortcut( "live" );
64
65     add_submodule();
66         set_description( _("RTSP/RTP describe") );
67         add_shortcut( "rtsp" );
68         set_capability( "access", 0 );
69         set_callbacks( AccessOpen, AccessClose );
70         add_category_hint( N_("RTSP"), NULL, VLC_TRUE );
71             add_bool( "rtsp-tcp", 0, NULL,
72                       "Use rtp over rtsp(tcp)",
73                       "Use rtp over rtsp(tcp)", VLC_TRUE );
74             add_integer( "rtsp-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
75 vlc_module_end();
76
77 /* TODO:
78  *  - Support PS/TS (need to rework the TS/PS demuxer a lot).
79  *  - Support X-QT/X-QUICKTIME generic codec for audio.
80  *
81  *  - Check memory leak, delete/free -> still one when using rtsp-tcp but I'm
82  *  not sure if it comes from me.
83  *
84  */
85
86 /*****************************************************************************
87  * Local prototypes
88  *****************************************************************************/
89 struct access_sys_t
90 {
91     int     i_sdp;
92     char    *p_sdp;
93
94     int     i_pos;
95 };
96
97 typedef struct
98 {
99     input_thread_t *p_input;
100
101     vlc_bool_t   b_quicktime;
102
103     es_format_t  fmt;
104     es_out_id_t  *p_es;
105
106     RTPSource    *rtpSource;
107     FramedSource *readSource;
108
109     uint8_t      buffer[65536];
110
111     char         waiting;
112
113     mtime_t      i_pts;
114 } live_track_t;
115
116 struct demux_sys_t
117 {
118     char         *p_sdp;    /* XXX mallocated */
119
120     MediaSession     *ms;
121     TaskScheduler    *scheduler;
122     UsageEnvironment *env ;
123     RTSPClient       *rtsp;
124
125     int              i_track;
126     live_track_t     **track;   /* XXX mallocated */
127     mtime_t          i_pcr;
128     mtime_t          i_pcr_start;
129
130     mtime_t          i_length;
131     mtime_t          i_start;
132
133     char             event;
134 };
135
136 static ssize_t Read   ( input_thread_t *, byte_t *, size_t );
137
138 static int     Demux  ( input_thread_t * );
139 static int     Control( input_thread_t *, int, va_list );
140
141
142
143 /*****************************************************************************
144  * AccessOpen:
145  *****************************************************************************/
146 static int  AccessOpen( vlc_object_t *p_this )
147 {
148     input_thread_t *p_input = (input_thread_t *)p_this;
149     access_sys_t   *p_sys;
150
151     TaskScheduler    *scheduler = NULL;
152     UsageEnvironment *env       = NULL;
153     RTSPClient       *rtsp      = NULL;
154
155     vlc_value_t      val;
156     char             *psz_url;
157
158     if( p_input->psz_access == NULL || strcasecmp( p_input->psz_access, "rtsp" ) )
159     {
160         msg_Warn( p_input, "RTSP access discarded" );
161         return VLC_EGENERIC;
162     }
163     if( ( scheduler = BasicTaskScheduler::createNew() ) == NULL )
164     {
165         msg_Err( p_input, "BasicTaskScheduler::createNew failed" );
166         return VLC_EGENERIC;
167     }
168     if( ( env = BasicUsageEnvironment::createNew(*scheduler) ) == NULL )
169     {
170         delete scheduler;
171         msg_Err( p_input, "BasicUsageEnvironment::createNew failed" );
172         return VLC_EGENERIC;
173     }
174     if( ( rtsp = RTSPClient::createNew(*env, 1/*verbose*/, "VLC Media Player" ) ) == NULL )
175     {
176         delete env;
177         delete scheduler;
178         msg_Err( p_input, "RTSPClient::createNew failed" );
179         return VLC_EGENERIC;
180     }
181
182     psz_url = (char*)malloc( strlen( p_input->psz_name ) + 8 );
183     sprintf( psz_url, "rtsp://%s", p_input->psz_name );
184
185     p_sys = (access_sys_t*)malloc( sizeof( access_sys_t ) );
186     p_sys->p_sdp = rtsp->describeURL( psz_url );
187
188     if( p_sys->p_sdp == NULL )
189     {
190         msg_Err( p_input, "describeURL failed (%s)", env->getResultMsg() );
191
192         free( psz_url );
193         delete env;
194         delete scheduler;
195         free( p_sys );
196         return VLC_EGENERIC;
197     }
198     free( psz_url );
199     p_sys->i_sdp = strlen( p_sys->p_sdp );
200     p_sys->i_pos = 0;
201
202     //fprintf( stderr, "sdp=%s\n", p_sys->p_sdp );
203
204     delete env;
205     delete scheduler;
206
207     var_Create( p_input, "rtsp-tcp", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
208     var_Get( p_input, "rtsp-tcp", &val );
209
210     p_input->p_access_data = p_sys;
211     p_input->i_mtu = 0;
212
213     /* Set exported functions */
214     p_input->pf_read = Read;
215     p_input->pf_seek = NULL;
216     p_input->pf_set_program = input_SetProgram;
217     p_input->pf_set_area = NULL;
218     p_input->p_private = NULL;
219
220     p_input->psz_demux = "live";
221
222     /* Finished to set some variable */
223     vlc_mutex_lock( &p_input->stream.stream_lock );
224     /* FIXME that's not true but eg over tcp, server send data too fast */
225     p_input->stream.b_pace_control = val.b_bool;
226     p_input->stream.p_selected_area->i_tell = 0;
227     p_input->stream.b_seekable = 1; /* Hack to display time */
228     p_input->stream.p_selected_area->i_size = 0;
229     p_input->stream.i_method = INPUT_METHOD_NETWORK;
230     vlc_mutex_unlock( &p_input->stream.stream_lock );
231
232     /* Update default_pts to a suitable value for RTSP access */
233     var_Create( p_input, "rtsp-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
234     var_Get( p_input, "rtsp-caching", &val );
235     p_input->i_pts_delay = val.i_int * 1000;
236
237     return VLC_SUCCESS;
238 }
239
240 /*****************************************************************************
241  * AccessClose:
242  *****************************************************************************/
243 static void AccessClose( vlc_object_t *p_this )
244 {
245     input_thread_t *p_input = (input_thread_t *)p_this;
246     access_sys_t   *p_sys = p_input->p_access_data;
247
248     delete[] p_sys->p_sdp;
249     free( p_sys );
250 }
251
252 /*****************************************************************************
253  * Read:
254  *****************************************************************************/
255 static ssize_t Read ( input_thread_t *p_input, byte_t *p_buffer, size_t i_len )
256 {
257     access_sys_t   *p_sys   = p_input->p_access_data;
258     int            i_copy = __MIN( (int)i_len, p_sys->i_sdp - p_sys->i_pos );
259
260     if( i_copy > 0 )
261     {
262         memcpy( p_buffer, &p_sys->p_sdp[p_sys->i_pos], i_copy );
263         p_sys->i_pos += i_copy;
264     }
265     return i_copy;
266 }
267
268
269 /*****************************************************************************
270  * DemuxOpen:
271  *****************************************************************************/
272 static int  DemuxOpen ( vlc_object_t *p_this )
273 {
274     input_thread_t *p_input = (input_thread_t *)p_this;
275     demux_sys_t    *p_sys;
276
277     MediaSubsessionIterator *iter;
278     MediaSubsession *sub;
279
280     vlc_value_t val;
281
282     uint8_t *p_peek;
283
284     int     i_sdp;
285     int     i_sdp_max;
286     uint8_t *p_sdp;
287
288     /* See if it looks like a SDP
289        v, o, s fields are mandatory and in this order */
290     if( stream_Peek( p_input->s, &p_peek, 7 ) < 7 )
291     {
292         msg_Err( p_input, "cannot peek" );
293         return VLC_EGENERIC;
294     }
295     if( strncmp( (char*)p_peek, "v=0\r\n", 5 ) && strncmp( (char*)p_peek, "v=0\n", 4 ) &&
296         ( p_input->psz_access == NULL || strcasecmp( p_input->psz_access, "rtsp" ) ||
297           p_peek[0] < 'a' || p_peek[0] > 'z' || p_peek[1] != '=' ) )
298     {
299         msg_Warn( p_input, "SDP module discarded" );
300         return VLC_EGENERIC;
301     }
302
303     p_input->pf_demux = Demux;
304     p_input->pf_demux_control = Control;
305     p_input->p_demux_data = p_sys = (demux_sys_t*)malloc( sizeof( demux_sys_t ) );
306     p_sys->p_sdp = NULL;
307     p_sys->scheduler = NULL;
308     p_sys->env = NULL;
309     p_sys->ms = NULL;
310     p_sys->rtsp = NULL;
311     p_sys->i_track = 0;
312     p_sys->track   = NULL;
313     p_sys->i_pcr   = 0;
314     p_sys->i_pcr_start = 0;
315     p_sys->i_length = 0;
316     p_sys->i_start = 0;
317
318     /* Gather the complete sdp file */
319     i_sdp = 0;
320     i_sdp_max = 1000;
321     p_sdp = (uint8_t*)malloc( i_sdp_max );
322     for( ;; )
323     {
324         int i_read = stream_Read( p_input->s, &p_sdp[i_sdp], i_sdp_max - i_sdp - 1 );
325
326         if( i_read < 0 )
327         {
328             msg_Err( p_input, "failed to read SDP" );
329             free( p_sys );
330             return VLC_EGENERIC;
331         }
332
333         i_sdp += i_read;
334
335         if( i_read < i_sdp_max - i_sdp - 1 )
336         {
337             p_sdp[i_sdp] = '\0';
338             break;
339         }
340
341         i_sdp_max += 1000;
342         p_sdp = (uint8_t*)realloc( p_sdp, i_sdp_max );
343     }
344     p_sys->p_sdp = (char*)p_sdp;
345
346     fprintf( stderr, "sdp=%s\n", p_sys->p_sdp );
347
348     if( ( p_sys->scheduler = BasicTaskScheduler::createNew() ) == NULL )
349     {
350         msg_Err( p_input, "BasicTaskScheduler::createNew failed" );
351         goto error;
352     }
353     if( ( p_sys->env = BasicUsageEnvironment::createNew(*p_sys->scheduler) ) == NULL )
354     {
355         msg_Err( p_input, "BasicUsageEnvironment::createNew failed" );
356         goto error;
357     }
358     if( p_input->psz_access != NULL && !strcasecmp( p_input->psz_access, "rtsp" ) )
359     {
360         char *psz_url;
361         char *psz_options;
362
363         if( ( p_sys->rtsp = RTSPClient::createNew(*p_sys->env, 1/*verbose*/, "VLC Media Player" ) ) == NULL )
364         {
365             msg_Err( p_input, "RTSPClient::createNew failed (%s)", p_sys->env->getResultMsg() );
366             goto error;
367         }
368         psz_url = (char*)malloc( strlen( p_input->psz_name ) + 8 );
369         sprintf( psz_url, "rtsp://%s", p_input->psz_name );
370
371         psz_options = p_sys->rtsp->sendOptionsCmd( psz_url );
372         /* FIXME psz_options -> delete or free */
373         free( psz_url );
374     }
375     if( ( p_sys->ms = MediaSession::createNew(*p_sys->env, p_sys->p_sdp ) ) == NULL )
376     {
377         msg_Err( p_input, "MediaSession::createNew failed" );
378         goto error;
379     }
380
381     var_Create( p_input, "rtsp-tcp", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
382     var_Get( p_input, "rtsp-tcp", &val );
383
384     /* Initialise each media subsession */
385     iter = new MediaSubsessionIterator( *p_sys->ms );
386     while( ( sub = iter->next() ) != NULL )
387     {
388         unsigned int i_buffer = 0;
389
390         /* Value taken from mplayer */
391         if( !strcmp( sub->mediumName(), "audio" ) )
392         {
393             i_buffer = 100000;
394         }
395         else if( !strcmp( sub->mediumName(), "video" ) )
396         {
397             i_buffer = 2000000;
398         }
399         else
400         {
401             continue;
402         }
403
404         if( !sub->initiate() )
405         {
406             msg_Warn( p_input, "RTP subsession '%s/%s' failed(%s)", sub->mediumName(), sub->codecName(), p_sys->env->getResultMsg() );
407         }
408         else
409         {
410             int fd = sub->rtpSource()->RTPgs()->socketNum();
411
412             msg_Dbg( p_input, "RTP subsession '%s/%s'", sub->mediumName(), sub->codecName() );
413
414             /* Increase the buffer size */
415             increaseReceiveBufferTo( *p_sys->env, fd, i_buffer );
416             /* Issue the SETUP */
417             if( p_sys->rtsp )
418             {
419                 p_sys->rtsp->setupMediaSubsession( *sub, False, val.b_bool ? True : False );
420             }
421         }
422     }
423
424     if( p_sys->rtsp )
425     {
426         /* The PLAY */
427         if( !p_sys->rtsp->playMediaSession( *p_sys->ms ) )
428         {
429             msg_Err( p_input, "PLAY failed %s", p_sys->env->getResultMsg() );
430             goto error;
431         }
432     }
433
434     /* Create all es struct */
435     iter->reset();
436     while( ( sub = iter->next() ) != NULL )
437     {
438         live_track_t *tk;
439
440         if( sub->readSource() == NULL )
441         {
442             continue;
443         }
444
445         tk = (live_track_t*)malloc( sizeof( live_track_t ) );
446         tk->p_input = p_input;
447         tk->waiting = 0;
448         tk->i_pts   = 0;
449         tk->b_quicktime = VLC_FALSE;
450
451         /* Value taken from mplayer */
452         if( !strcmp( sub->mediumName(), "audio" ) )
453         {
454             es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC( 'u', 'n', 'd', 'f' ) );
455             tk->fmt.audio.i_channels = sub->numChannels();
456             tk->fmt.audio.i_rate = sub->rtpSource()->timestampFrequency();
457
458             if( !strcmp( sub->codecName(), "MPA" ) ||
459                 !strcmp( sub->codecName(), "MPA-ROBUST" ) ||
460                 !strcmp( sub->codecName(), "X-MP3-DRAFT-00" ) )
461             {
462                 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
463                 tk->fmt.audio.i_rate = 0;
464             }
465             else if( !strcmp( sub->codecName(), "AC3" ) )
466             {
467                 tk->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
468                 tk->fmt.audio.i_rate = 0;
469             }
470             else if( !strcmp( sub->codecName(), "L16" ) )
471             {
472                 tk->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
473                 tk->fmt.audio.i_bitspersample = 16;
474             }
475             else if( !strcmp( sub->codecName(), "L8" ) )
476             {
477                 tk->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
478                 tk->fmt.audio.i_bitspersample = 8;
479             }
480             else if( !strcmp( sub->codecName(), "PCMU" ) )
481             {
482                 tk->fmt.i_codec = VLC_FOURCC( 'u', 'l', 'a', 'w' );
483             }
484             else if( !strcmp( sub->codecName(), "PCMA" ) )
485             {
486                 tk->fmt.i_codec = VLC_FOURCC( 'a', 'l', 'a', 'w' );
487             }
488             else if( !strcmp( sub->codecName(), "MP4A-LATM" ) )
489             {
490                 unsigned int i_extra;
491                 uint8_t      *p_extra;
492
493                 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
494
495                 if( ( p_extra = parseStreamMuxConfigStr( sub->fmtp_config(), i_extra ) ) )
496                 {
497                     tk->fmt.i_extra = i_extra;
498                     tk->fmt.p_extra = malloc( sizeof( i_extra ) );
499                     memcpy( tk->fmt.p_extra, p_extra, i_extra );
500                     delete[] p_extra;
501                 }
502             }
503             else if( !strcmp( sub->codecName(), "MPEG4-GENERIC" ) )
504             {
505                 unsigned int i_extra;
506                 uint8_t      *p_extra;
507
508                 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
509
510                 if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(), i_extra ) ) )
511                 {
512                     tk->fmt.i_extra = i_extra;
513                     tk->fmt.p_extra = malloc( i_extra );
514                     memcpy( tk->fmt.p_extra, p_extra, i_extra );
515                     delete[] p_extra;
516                 }
517             }
518         }
519         else if( !strcmp( sub->mediumName(), "video" ) )
520         {
521             es_format_Init( &tk->fmt, VIDEO_ES, VLC_FOURCC( 'u', 'n', 'd', 'f' ) );
522             if( !strcmp( sub->codecName(), "MPV" ) )
523             {
524                 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'v' );
525             }
526             else if( !strcmp( sub->codecName(), "H263" ) ||
527                      !strcmp( sub->codecName(), "H263-1998" ) )
528             {
529                 tk->fmt.i_codec = VLC_FOURCC( 'h', '2', '6', '3' );
530             }
531             else if( !strcmp( sub->codecName(), "H261" ) )
532             {
533                 tk->fmt.i_codec = VLC_FOURCC( 'h', '2', '6', '1' );
534             }
535             else if( !strcmp( sub->codecName(), "JPEG" ) )
536             {
537                 tk->fmt.i_codec = VLC_FOURCC( 'M', 'J', 'P', 'G' );
538             }
539             else if( !strcmp( sub->codecName(), "MP4V-ES" ) )
540             {
541                 unsigned int i_extra;
542                 uint8_t      *p_extra;
543
544                 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' );
545
546                 if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(), i_extra ) ) )
547                 {
548                     tk->fmt.i_extra = i_extra;
549                     tk->fmt.p_extra = malloc( i_extra );
550                     memcpy( tk->fmt.p_extra, p_extra, i_extra );
551                     delete[] p_extra;
552                 }
553             }
554             else if( !strcmp( sub->codecName(), "X-QT" ) || !strcmp( sub->codecName(), "X-QUICKTIME" ) )
555             {
556                 tk->b_quicktime = VLC_TRUE;
557             }
558         }
559
560         if( tk->fmt.i_codec != VLC_FOURCC( 'u', 'n', 'd', 'f' ) )
561         {
562             tk->p_es = es_out_Add( p_input->p_es_out, &tk->fmt );
563         }
564         else
565         {
566             tk->p_es = NULL;
567         }
568
569         if( tk->p_es || tk->b_quicktime )
570         {
571             TAB_APPEND( p_sys->i_track, (void**)p_sys->track, (void*)tk );
572             tk->readSource = sub->readSource();
573             tk->rtpSource  = sub->rtpSource();
574         }
575         else
576         {
577             free( tk );
578         }
579     }
580
581     delete iter;
582
583     p_sys->i_length = (mtime_t)(p_sys->ms->playEndTime() * 1000000.0);
584     if( p_sys->i_length < 0 )
585     {
586         p_sys->i_length = 0;
587     }
588     else if( p_sys->i_length > 0 )
589     {
590         p_input->stream.p_selected_area->i_size = 1000; /* needed for now */
591     }
592
593     if( p_sys->i_track <= 0 )
594     {
595         msg_Err( p_input, "No codec supported, aborting" );
596         goto error;
597     }
598
599     return VLC_SUCCESS;
600
601 error:
602     if( p_sys->ms )
603     {
604         Medium::close( p_sys->ms );
605     }
606     if( p_sys->rtsp )
607     {
608         Medium::close( p_sys->rtsp );
609     }
610     if( p_sys->env )
611     {
612         delete p_sys->env;
613     }
614     if( p_sys->scheduler )
615     {
616         delete p_sys->scheduler;
617     }
618     if( p_sys->p_sdp )
619     {
620         free( p_sys->p_sdp );
621     }
622     free( p_sys );
623     return VLC_EGENERIC;
624 }
625
626
627
628 /*****************************************************************************
629  * DemuxClose:
630  *****************************************************************************/
631 static void DemuxClose( vlc_object_t *p_this )
632 {
633     input_thread_t *p_input = (input_thread_t *)p_this;
634     demux_sys_t    *p_sys = p_input->p_demux_data;
635     int            i;
636
637     for( i = 0; i < p_sys->i_track; i++ )
638     {
639         live_track_t *tk = p_sys->track[i];
640
641         free( tk );
642     }
643     if( p_sys->i_track )
644     {
645         free( p_sys->track );
646     }
647
648     if( p_sys->rtsp && p_sys->ms )
649     {
650         /* TEARDOWN */
651         p_sys->rtsp->teardownMediaSession( *p_sys->ms );
652     }
653     Medium::close( p_sys->ms );
654     if( p_sys->rtsp )
655     {
656         Medium::close( p_sys->rtsp );
657     }
658
659     if( p_sys->env )
660     {
661         delete p_sys->env;
662     }
663     if( p_sys->scheduler )
664     {
665         delete p_sys->scheduler;
666     }
667     if( p_sys->p_sdp )
668     {
669         free( p_sys->p_sdp );
670     }
671     free( p_sys );
672 }
673
674
675 static void StreamRead( void *p_private, unsigned int i_size, struct timeval pts );
676 static void StreamClose( void *p_private );
677 static void TaskInterrupt( void *p_private );
678
679 /*****************************************************************************
680  * Demux:
681  *****************************************************************************/
682 static int  Demux   ( input_thread_t *p_input )
683 {
684     demux_sys_t    *p_sys = p_input->p_demux_data;
685     TaskToken      task;
686
687     mtime_t         i_pcr = 0;
688     int             i;
689
690     for( i = 0; i < p_sys->i_track; i++ )
691     {
692         live_track_t *tk = p_sys->track[i];
693
694         if( i_pcr == 0 )
695         {
696             i_pcr = tk->i_pts;
697         }
698         else if( tk->i_pts != 0 && i_pcr > tk->i_pts )
699         {
700             i_pcr = tk->i_pts ;
701         }
702     }
703     if( i_pcr != p_sys->i_pcr && i_pcr > 0 )
704     {
705         input_ClockManageRef( p_input,
706                               p_input->stream.p_selected_program,
707                               i_pcr * 9 / 100 );
708         p_sys->i_pcr = i_pcr;
709         if( p_sys->i_pcr_start <= 0 || p_sys->i_pcr_start > i_pcr )
710         {
711             p_sys->i_pcr_start = i_pcr;
712         }
713     }
714
715     /* First warm we want to read data */
716     p_sys->event = 0;
717     for( i = 0; i < p_sys->i_track; i++ )
718     {
719         live_track_t *tk = p_sys->track[i];
720
721         if( tk->waiting == 0 )
722         {
723             tk->waiting = 1;
724             tk->readSource->getNextFrame( tk->buffer, 65536,
725                                           StreamRead, tk,
726                                           StreamClose, tk );
727         }
728     }
729     /* Create a task that will be called if we wait more than 300ms */
730     task = p_sys->scheduler->scheduleDelayedTask( 300000, TaskInterrupt, p_input );
731
732     /* Do the read */
733     p_sys->scheduler->doEventLoop( &p_sys->event );
734
735     /* remove the task */
736     p_sys->scheduler->unscheduleDelayedTask( task );
737
738     return p_input->b_error ? 0 : 1;
739 }
740
741 static int    Control( input_thread_t *p_input, int i_query, va_list args )
742 {
743     demux_sys_t *p_sys = p_input->p_demux_data;
744     int64_t *pi64;
745     double  *pf, f;
746
747     switch( i_query )
748     {
749         case DEMUX_GET_TIME:
750             pi64 = (int64_t*)va_arg( args, int64_t * );
751             *pi64 = p_sys->i_pcr - p_sys->i_pcr_start + p_sys->i_start;
752             return VLC_SUCCESS;
753
754         case DEMUX_GET_LENGTH:
755             pi64 = (int64_t*)va_arg( args, int64_t * );
756             *pi64 = p_sys->i_length;
757             return VLC_SUCCESS;
758
759         case DEMUX_GET_POSITION:
760             pf = (double*)va_arg( args, double* );
761             if( p_sys->i_length > 0 )
762             {
763                 *pf = (double)( p_sys->i_pcr - p_sys->i_pcr_start + p_sys->i_start)/
764                       (double)(p_sys->i_length);
765             }
766             else
767             {
768                 *pf = 0;
769             }
770             return VLC_SUCCESS;
771
772         case DEMUX_SET_POSITION:
773         {
774             float time;
775
776             f = (double)va_arg( args, double );
777             time = f * (double)p_sys->i_length / 1000000.0;   /* in second */
778
779             if( p_sys->rtsp && p_sys->i_length > 0 )
780             {
781                 MediaSubsessionIterator *iter = new MediaSubsessionIterator( *p_sys->ms );
782                 MediaSubsession         *sub;
783                 int i;
784
785                 while( ( sub = iter->next() ) != NULL )
786                 {
787                     p_sys->rtsp->playMediaSubsession( *sub, time );
788                 }
789                 delete iter;
790                 p_sys->i_start = (mtime_t)(f * (double)p_sys->i_length);
791                 p_sys->i_pcr_start = 0;
792                 p_sys->i_pcr       = 0;
793                 for( i = 0; i < p_sys->i_track; i++ )
794                 {
795                     p_sys->track[i]->i_pts = 0;
796                 }
797                 return VLC_SUCCESS;
798             }
799             return VLC_EGENERIC;
800         }
801
802         default:
803             return demux_vaControlDefault( p_input, i_query, args );
804     }
805 }
806
807 /*****************************************************************************
808  *
809  *****************************************************************************/
810 static void StreamRead( void *p_private, unsigned int i_size, struct timeval pts )
811 {
812     live_track_t   *tk = (live_track_t*)p_private;
813     input_thread_t *p_input = tk->p_input;
814     demux_sys_t    *p_sys = p_input->p_demux_data;
815     pes_packet_t   *p_pes;
816     data_packet_t  *p_data;
817
818     mtime_t        i_pts = (mtime_t)pts.tv_sec * 1000000LL + (mtime_t)pts.tv_usec;
819
820     if( tk->b_quicktime && tk->p_es == NULL )
821     {
822         QuickTimeGenericRTPSource *qtRTPSource = (QuickTimeGenericRTPSource*)tk->rtpSource;
823         QuickTimeGenericRTPSource::QTState &qtState = qtRTPSource->qtState;
824         uint8_t *sdAtom = (uint8_t*)&qtState.sdAtom[4];
825
826         if( qtState.sdAtomSize < 16 + 32 )
827         {
828             /* invalid */
829             p_sys->event = 0xff;
830             tk->waiting = 0;
831             return;
832         }
833         tk->fmt.i_codec = VLC_FOURCC( sdAtom[0], sdAtom[1], sdAtom[2], sdAtom[3] );
834         tk->fmt.video.i_width  = (sdAtom[28] << 8) | sdAtom[29];
835         tk->fmt.video.i_height = (sdAtom[30] << 8) | sdAtom[31];
836
837         tk->fmt.i_extra        = qtState.sdAtomSize - 16;
838         tk->fmt.p_extra        = malloc( tk->fmt.i_extra );
839         memcpy( tk->fmt.p_extra, &sdAtom[12], tk->fmt.i_extra );
840
841         tk->p_es = es_out_Add( p_input->p_es_out, &tk->fmt );
842     }
843
844 #if 0
845     fprintf( stderr, "StreamRead size=%d pts=%lld\n",
846              i_size,
847              pts.tv_sec * 1000000LL + pts.tv_usec );
848 #endif
849     /* Create a PES */
850     if( ( p_pes = input_NewPES( p_input->p_method_data ) ) == NULL )
851     {
852         return;
853     }
854     if( i_size > 65536 )
855     {
856         msg_Warn( p_input, "buffer overflow" );
857     }
858     /* FIXME could i_size be > buffer size ? */
859     p_data = input_NewPacket( p_input->p_method_data, i_size );
860
861     memcpy( p_data->p_payload_start, tk->buffer, i_size );
862     p_data->p_payload_end = p_data->p_payload_start + i_size;
863
864     p_pes->p_first = p_pes->p_last = p_data;
865     p_pes->i_nb_data = 1;
866     p_pes->i_pes_size = i_size;
867     p_pes->i_rate = p_input->stream.control.i_rate;
868
869     if( i_pts != tk->i_pts )
870     {
871         p_pes->i_dts =
872         p_pes->i_pts = input_ClockGetTS( p_input,
873                                          p_input->stream.p_selected_program,
874                                          i_pts * 9 / 100 );
875     }
876     else
877     {
878         p_pes->i_dts = 0;
879         p_pes->i_pts = 0;
880     }
881     //fprintf( stderr, "tk -> dpts=%lld\n", i_pts - tk->i_pts );
882
883     es_out_Send( p_input->p_es_out, tk->p_es, p_pes );
884
885     /* warm that's ok */
886     p_sys->event = 0xff;
887
888     /* we have read data */
889     tk->waiting = 0;
890
891     if( i_pts > 0 )
892     {
893         tk->i_pts = i_pts;
894     }
895 }
896
897 /*****************************************************************************
898  *
899  *****************************************************************************/
900 static void StreamClose( void *p_private )
901 {
902     live_track_t   *tk = (live_track_t*)p_private;
903     input_thread_t *p_input = tk->p_input;
904     demux_sys_t    *p_sys = p_input->p_demux_data;
905
906     fprintf( stderr, "StreamClose\n" );
907
908     p_sys->event = 0xff;
909     p_input->b_error = VLC_TRUE;
910 }
911
912
913 /*****************************************************************************
914  *
915  *****************************************************************************/
916 static void TaskInterrupt( void *p_private )
917 {
918     input_thread_t *p_input = (input_thread_t*)p_private;
919
920     fprintf( stderr, "TaskInterrupt\n" );
921
922     /* Avoid lock */
923     p_input->p_demux_data->event = 0xff;
924 }
925