1 /*****************************************************************************
2 * live.cpp : live.com support.
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
30 #include <vlc/input.h>
32 #include <codecs.h> /* BITMAPINFOHEADER, WAVEFORMATEX */
36 # include <winsock2.h>
39 #include "BasicUsageEnvironment.hh"
40 #include "GroupsockHelper.hh"
41 #include "liveMedia.hh"
45 /*****************************************************************************
47 *****************************************************************************/
48 static int DemuxOpen ( vlc_object_t * );
49 static void DemuxClose( vlc_object_t * );
51 static int AccessOpen ( vlc_object_t * );
52 static void AccessClose( vlc_object_t * );
54 #define CACHING_TEXT N_("Caching value (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." )
60 set_description( _("live.com (RTSP/RTP/SDP) demuxer" ) );
61 set_capability( "demux", 50 );
62 set_callbacks( DemuxOpen, DemuxClose );
63 add_shortcut( "live" );
66 set_description( _("RTSP/RTP describe") );
67 add_shortcut( "rtsp" );
68 add_shortcut( "sdp" );
69 set_capability( "access", 0 );
70 set_callbacks( AccessOpen, AccessClose );
71 add_bool( "rtsp-tcp", 0, NULL,
72 N_("Use RTP over RTSP (TCP)"),
73 N_("Use RTP over RTSP (TCP)"), VLC_TRUE );
74 add_integer( "rtsp-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL,
75 CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
79 * - Support PS/TS (need to rework the TS/PS demuxer a lot).
80 * - Support X-QT/X-QUICKTIME generic codec for audio.
82 * - Check memory leak, delete/free -> still one when using rtsp-tcp but I'm
83 * not sure if it comes from me.
87 /*****************************************************************************
89 *****************************************************************************/
100 input_thread_t *p_input;
102 vlc_bool_t b_quicktime;
108 stream_t *p_out_muxed; /* for muxed stream */
110 RTPSource *rtpSource;
111 FramedSource *readSource;
112 vlc_bool_t b_rtcp_sync;
114 uint8_t buffer[65536];
123 char *p_sdp; /* XXX mallocated */
126 TaskScheduler *scheduler;
127 UsageEnvironment *env ;
131 live_track_t **track; /* XXX mallocated */
141 static ssize_t Read ( input_thread_t *, byte_t *, size_t );
142 static ssize_t MRLRead( input_thread_t *, byte_t *, size_t );
144 static int Demux ( input_thread_t * );
145 static int Control( input_thread_t *, int, va_list );
149 /*****************************************************************************
151 *****************************************************************************/
152 static int AccessOpen( vlc_object_t *p_this )
154 input_thread_t *p_input = (input_thread_t *)p_this;
157 TaskScheduler *scheduler = NULL;
158 UsageEnvironment *env = NULL;
159 RTSPClient *rtsp = NULL;
164 if( p_input->psz_access == NULL || ( strcasecmp( p_input->psz_access, "rtsp" ) && strcasecmp( p_input->psz_access, "sdp" ) ) )
166 msg_Warn( p_input, "RTSP access discarded" );
169 if( !strcasecmp( p_input->psz_access, "rtsp" ) )
171 if( ( scheduler = BasicTaskScheduler::createNew() ) == NULL )
173 msg_Err( p_input, "BasicTaskScheduler::createNew failed" );
176 if( ( env = BasicUsageEnvironment::createNew(*scheduler) ) == NULL )
179 msg_Err( p_input, "BasicUsageEnvironment::createNew failed" );
182 if( ( rtsp = RTSPClient::createNew(*env, 1/*verbose*/, "VLC Media Player" ) ) == NULL )
186 msg_Err( p_input, "RTSPClient::createNew failed" );
190 psz_url = (char*)malloc( strlen( p_input->psz_name ) + 8 );
191 sprintf( psz_url, "rtsp://%s", p_input->psz_name );
193 p_sys = (access_sys_t*)malloc( sizeof( access_sys_t ) );
194 p_sys->p_sdp = rtsp->describeURL( psz_url );
196 if( p_sys->p_sdp == NULL )
198 msg_Err( p_input, "describeURL failed (%s)", env->getResultMsg() );
207 p_sys->i_sdp = strlen( p_sys->p_sdp );
210 //fprintf( stderr, "sdp=%s\n", p_sys->p_sdp );
215 var_Create( p_input, "rtsp-tcp", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
216 var_Get( p_input, "rtsp-tcp", &val );
218 p_input->p_access_data = p_sys;
221 /* Set exported functions */
222 p_input->pf_read = Read;
223 p_input->pf_seek = NULL;
224 p_input->pf_set_program = input_SetProgram;
225 p_input->pf_set_area = NULL;
226 p_input->p_private = NULL;
228 p_input->psz_demux = "live";
230 /* Finished to set some variable */
231 vlc_mutex_lock( &p_input->stream.stream_lock );
232 /* FIXME that's not true but eg over tcp, server send data too fast */
233 p_input->stream.b_pace_control = val.b_bool;
234 p_input->stream.p_selected_area->i_tell = 0;
235 p_input->stream.b_seekable = 1; /* Hack to display time */
236 p_input->stream.p_selected_area->i_size = 0;
237 p_input->stream.i_method = INPUT_METHOD_NETWORK;
238 vlc_mutex_unlock( &p_input->stream.stream_lock );
240 /* Update default_pts to a suitable value for RTSP access */
241 var_Create( p_input, "rtsp-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
242 var_Get( p_input, "rtsp-caching", &val );
243 p_input->i_pts_delay = val.i_int * 1000;
249 p_input->p_access_data = (access_sys_t*)0;
251 p_input->pf_read = MRLRead;
252 p_input->pf_seek = NULL;
253 p_input->pf_set_program = input_SetProgram;
254 p_input->pf_set_area = NULL;
255 p_input->p_private = NULL;
256 p_input->psz_demux = "live";
257 /* Finished to set some variable */
258 vlc_mutex_lock( &p_input->stream.stream_lock );
259 p_input->stream.b_pace_control = VLC_TRUE;
260 p_input->stream.p_selected_area->i_tell = 0;
261 p_input->stream.b_seekable = VLC_FALSE;
262 p_input->stream.p_selected_area->i_size = 0;
263 p_input->stream.i_method = INPUT_METHOD_NETWORK;
264 vlc_mutex_unlock( &p_input->stream.stream_lock );
270 /*****************************************************************************
272 *****************************************************************************/
273 static void AccessClose( vlc_object_t *p_this )
275 input_thread_t *p_input = (input_thread_t *)p_this;
276 access_sys_t *p_sys = p_input->p_access_data;
277 if( !strcasecmp( p_input->psz_access, "rtsp" ) )
279 delete[] p_sys->p_sdp;
284 /*****************************************************************************
286 *****************************************************************************/
287 static ssize_t Read ( input_thread_t *p_input, byte_t *p_buffer, size_t i_len )
289 access_sys_t *p_sys = p_input->p_access_data;
290 int i_copy = __MIN( (int)i_len, p_sys->i_sdp - p_sys->i_pos );
294 memcpy( p_buffer, &p_sys->p_sdp[p_sys->i_pos], i_copy );
295 p_sys->i_pos += i_copy;
299 /*****************************************************************************
300 * MRLRead: read data from the mrl
301 *****************************************************************************/
302 static ssize_t MRLRead ( input_thread_t *p_input, byte_t *p_buffer, size_t i_len )
304 int i_done = (int)p_input->p_access_data;
305 int i_copy = __MIN( (int)i_len, (int)strlen(p_input->psz_name) - i_done );
309 memcpy( p_buffer, &p_input->psz_name[i_done], i_copy );
311 p_input->p_access_data = (access_sys_t*)i_done;
317 /*****************************************************************************
319 *****************************************************************************/
320 static int DemuxOpen ( vlc_object_t *p_this )
322 input_thread_t *p_input = (input_thread_t *)p_this;
325 MediaSubsessionIterator *iter;
326 MediaSubsession *sub;
336 /* See if it looks like a SDP
337 v, o, s fields are mandatory and in this order */
338 if( stream_Peek( p_input->s, &p_peek, 7 ) < 7 )
340 msg_Err( p_input, "cannot peek" );
343 if( strncmp( (char*)p_peek, "v=0\r\n", 5 ) && strncmp( (char*)p_peek, "v=0\n", 4 ) &&
344 ( p_input->psz_access == NULL || strcasecmp( p_input->psz_access, "rtsp" ) ||
345 p_peek[0] < 'a' || p_peek[0] > 'z' || p_peek[1] != '=' ) )
347 msg_Warn( p_input, "SDP module discarded" );
351 p_input->pf_demux = Demux;
352 p_input->pf_demux_control = Control;
353 p_input->p_demux_data = p_sys = (demux_sys_t*)malloc( sizeof( demux_sys_t ) );
355 p_sys->scheduler = NULL;
362 p_sys->i_pcr_start = 0;
366 /* Gather the complete sdp file */
367 vlc_mutex_lock( &p_input->stream.stream_lock );
368 if( input_InitStream( p_input, 0 ) == -1)
370 vlc_mutex_unlock( &p_input->stream.stream_lock );
371 msg_Err( p_input, "cannot init stream" );
374 vlc_mutex_unlock( &p_input->stream.stream_lock );
378 p_sdp = (uint8_t*)malloc( i_sdp_max );
381 int i_read = stream_Read( p_input->s, &p_sdp[i_sdp], i_sdp_max - i_sdp - 1 );
385 msg_Err( p_input, "failed to read SDP" );
392 if( i_read < i_sdp_max - i_sdp - 1 )
399 p_sdp = (uint8_t*)realloc( p_sdp, i_sdp_max );
401 p_sys->p_sdp = (char*)p_sdp;
403 fprintf( stderr, "sdp=%s\n", p_sys->p_sdp );
405 if( ( p_sys->scheduler = BasicTaskScheduler::createNew() ) == NULL )
407 msg_Err( p_input, "BasicTaskScheduler::createNew failed" );
410 if( ( p_sys->env = BasicUsageEnvironment::createNew(*p_sys->scheduler) ) == NULL )
412 msg_Err( p_input, "BasicUsageEnvironment::createNew failed" );
415 if( p_input->psz_access != NULL && !strcasecmp( p_input->psz_access, "rtsp" ) )
420 if( ( p_sys->rtsp = RTSPClient::createNew(*p_sys->env, 1/*verbose*/, "VLC Media Player" ) ) == NULL )
422 msg_Err( p_input, "RTSPClient::createNew failed (%s)", p_sys->env->getResultMsg() );
425 psz_url = (char*)malloc( strlen( p_input->psz_name ) + 8 );
426 sprintf( psz_url, "rtsp://%s", p_input->psz_name );
428 psz_options = p_sys->rtsp->sendOptionsCmd( psz_url );
429 /* FIXME psz_options -> delete or free */
432 if( ( p_sys->ms = MediaSession::createNew(*p_sys->env, p_sys->p_sdp ) ) == NULL )
434 msg_Err( p_input, "MediaSession::createNew failed" );
438 var_Create( p_input, "rtsp-tcp", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
439 var_Get( p_input, "rtsp-tcp", &val );
441 /* Initialise each media subsession */
442 iter = new MediaSubsessionIterator( *p_sys->ms );
443 while( ( sub = iter->next() ) != NULL )
445 unsigned int i_buffer = 0;
447 /* Value taken from mplayer */
448 if( !strcmp( sub->mediumName(), "audio" ) )
452 else if( !strcmp( sub->mediumName(), "video" ) )
461 if( !sub->initiate() )
463 msg_Warn( p_input, "RTP subsession '%s/%s' failed(%s)", sub->mediumName(), sub->codecName(), p_sys->env->getResultMsg() );
467 int fd = sub->rtpSource()->RTPgs()->socketNum();
469 msg_Dbg( p_input, "RTP subsession '%s/%s'", sub->mediumName(), sub->codecName() );
471 /* Increase the buffer size */
472 increaseReceiveBufferTo( *p_sys->env, fd, i_buffer );
473 /* Issue the SETUP */
476 p_sys->rtsp->setupMediaSubsession( *sub, False, val.b_bool ? True : False );
484 if( !p_sys->rtsp->playMediaSession( *p_sys->ms ) )
486 msg_Err( p_input, "PLAY failed %s", p_sys->env->getResultMsg() );
491 /* Create all es struct */
493 while( ( sub = iter->next() ) != NULL )
497 if( sub->readSource() == NULL )
502 tk = (live_track_t*)malloc( sizeof( live_track_t ) );
503 tk->p_input = p_input;
506 tk->b_quicktime = VLC_FALSE;
507 tk->b_muxed = VLC_FALSE;
508 tk->b_rtcp_sync = VLC_FALSE;
509 tk->p_out_muxed = NULL;
512 /* Value taken from mplayer */
513 if( !strcmp( sub->mediumName(), "audio" ) )
515 es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC( 'u', 'n', 'd', 'f' ) );
516 tk->fmt.audio.i_channels = sub->numChannels();
517 tk->fmt.audio.i_rate = sub->rtpSource()->timestampFrequency();
519 if( !strcmp( sub->codecName(), "MPA" ) ||
520 !strcmp( sub->codecName(), "MPA-ROBUST" ) ||
521 !strcmp( sub->codecName(), "X-MP3-DRAFT-00" ) )
523 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
524 tk->fmt.audio.i_rate = 0;
526 else if( !strcmp( sub->codecName(), "AC3" ) )
528 tk->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
529 tk->fmt.audio.i_rate = 0;
531 else if( !strcmp( sub->codecName(), "L16" ) )
533 tk->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
534 tk->fmt.audio.i_bitspersample = 16;
536 else if( !strcmp( sub->codecName(), "L8" ) )
538 tk->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
539 tk->fmt.audio.i_bitspersample = 8;
541 else if( !strcmp( sub->codecName(), "PCMU" ) )
543 tk->fmt.i_codec = VLC_FOURCC( 'u', 'l', 'a', 'w' );
545 else if( !strcmp( sub->codecName(), "PCMA" ) )
547 tk->fmt.i_codec = VLC_FOURCC( 'a', 'l', 'a', 'w' );
549 else if( !strcmp( sub->codecName(), "MP4A-LATM" ) )
551 unsigned int i_extra;
554 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
556 if( ( p_extra = parseStreamMuxConfigStr( sub->fmtp_config(), i_extra ) ) )
558 tk->fmt.i_extra = i_extra;
559 tk->fmt.p_extra = malloc( i_extra );
560 memcpy( tk->fmt.p_extra, p_extra, i_extra );
564 else if( !strcmp( sub->codecName(), "MPEG4-GENERIC" ) )
566 unsigned int i_extra;
569 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
571 if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(), i_extra ) ) )
573 tk->fmt.i_extra = i_extra;
574 tk->fmt.p_extra = malloc( i_extra );
575 memcpy( tk->fmt.p_extra, p_extra, i_extra );
580 else if( !strcmp( sub->mediumName(), "video" ) )
582 es_format_Init( &tk->fmt, VIDEO_ES, VLC_FOURCC( 'u', 'n', 'd', 'f' ) );
583 if( !strcmp( sub->codecName(), "MPV" ) )
585 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'v' );
587 else if( !strcmp( sub->codecName(), "H263" ) ||
588 !strcmp( sub->codecName(), "H263-1998" ) )
590 tk->fmt.i_codec = VLC_FOURCC( 'h', '2', '6', '3' );
592 else if( !strcmp( sub->codecName(), "H261" ) )
594 tk->fmt.i_codec = VLC_FOURCC( 'h', '2', '6', '1' );
596 else if( !strcmp( sub->codecName(), "JPEG" ) )
598 tk->fmt.i_codec = VLC_FOURCC( 'M', 'J', 'P', 'G' );
600 else if( !strcmp( sub->codecName(), "MP4V-ES" ) )
602 unsigned int i_extra;
605 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' );
607 if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(), i_extra ) ) )
609 tk->fmt.i_extra = i_extra;
610 tk->fmt.p_extra = malloc( i_extra );
611 memcpy( tk->fmt.p_extra, p_extra, i_extra );
615 else if( !strcmp( sub->codecName(), "X-QT" ) || !strcmp( sub->codecName(), "X-QUICKTIME" ) )
617 tk->b_quicktime = VLC_TRUE;
619 else if( !strcmp( sub->codecName(), "MP2T" ) )
621 tk->b_muxed = VLC_TRUE;
622 tk->p_out_muxed = stream_DemuxNew( p_input, "ts2", p_input->p_es_out );
624 else if( !strcmp( sub->codecName(), "MP2P" ) || !strcmp( sub->codecName(), "MP1S" ) ) /* FIXME check MP1S */
626 tk->b_muxed = VLC_TRUE;
627 tk->p_out_muxed = stream_DemuxNew( p_input, "ps2", p_input->p_es_out );
631 if( tk->fmt.i_codec != VLC_FOURCC( 'u', 'n', 'd', 'f' ) )
633 tk->p_es = es_out_Add( p_input->p_es_out, &tk->fmt );
636 if( tk->p_es || tk->b_quicktime || tk->b_muxed )
638 tk->readSource = sub->readSource();
639 tk->rtpSource = sub->rtpSource();
642 p_sys->track = (live_track_t**)realloc( p_sys->track, sizeof( live_track_t ) * ( p_sys->i_track + 1 ) );
643 p_sys->track[p_sys->i_track++] = tk;
653 p_sys->i_length = (mtime_t)(p_sys->ms->playEndTime() * 1000000.0);
654 if( p_sys->i_length < 0 )
658 else if( p_sys->i_length > 0 )
660 p_input->stream.p_selected_area->i_size = 1000; /* needed for now */
663 if( p_sys->i_track <= 0 )
665 msg_Err( p_input, "no codec supported, aborting" );
674 Medium::close( p_sys->ms );
678 Medium::close( p_sys->rtsp );
684 if( p_sys->scheduler )
686 delete p_sys->scheduler;
690 free( p_sys->p_sdp );
698 /*****************************************************************************
700 *****************************************************************************/
701 static void DemuxClose( vlc_object_t *p_this )
703 input_thread_t *p_input = (input_thread_t *)p_this;
704 demux_sys_t *p_sys = p_input->p_demux_data;
707 for( i = 0; i < p_sys->i_track; i++ )
709 live_track_t *tk = p_sys->track[i];
713 stream_DemuxDelete( tk->p_out_muxed );
720 free( p_sys->track );
723 if( p_sys->rtsp && p_sys->ms )
726 p_sys->rtsp->teardownMediaSession( *p_sys->ms );
728 Medium::close( p_sys->ms );
731 Medium::close( p_sys->rtsp );
738 if( p_sys->scheduler )
740 delete p_sys->scheduler;
744 free( p_sys->p_sdp );
750 static void StreamRead( void *p_private, unsigned int i_size, struct timeval pts );
751 static void StreamClose( void *p_private );
752 static void TaskInterrupt( void *p_private );
754 /*****************************************************************************
756 *****************************************************************************/
757 static int Demux ( input_thread_t *p_input )
759 demux_sys_t *p_sys = p_input->p_demux_data;
765 for( i = 0; i < p_sys->i_track; i++ )
767 live_track_t *tk = p_sys->track[i];
773 else if( tk->i_pts != 0 && i_pcr > tk->i_pts )
778 if( i_pcr != p_sys->i_pcr && i_pcr > 0 )
780 input_ClockManageRef( p_input,
781 p_input->stream.p_selected_program,
783 p_sys->i_pcr = i_pcr;
784 if( p_sys->i_pcr_start <= 0 || p_sys->i_pcr_start > i_pcr )
786 p_sys->i_pcr_start = i_pcr;
790 /* First warm we want to read data */
792 for( i = 0; i < p_sys->i_track; i++ )
794 live_track_t *tk = p_sys->track[i];
796 if( tk->waiting == 0 )
799 tk->readSource->getNextFrame( tk->buffer, 65536,
804 /* Create a task that will be called if we wait more than 300ms */
805 task = p_sys->scheduler->scheduleDelayedTask( 300000, TaskInterrupt, p_input );
808 p_sys->scheduler->doEventLoop( &p_sys->event );
810 /* remove the task */
811 p_sys->scheduler->unscheduleDelayedTask( task );
813 /* Check for gap in pts value */
814 for( i = 0; i < p_sys->i_track; i++ )
816 live_track_t *tk = p_sys->track[i];
818 if( !tk->b_muxed && !tk->b_rtcp_sync && tk->rtpSource->hasBeenSynchronizedUsingRTCP() )
820 msg_Dbg( p_input, "tk->rtpSource->hasBeenSynchronizedUsingRTCP()" );
821 p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_REINIT;
822 tk->b_rtcp_sync = VLC_TRUE;
824 /* reset PCR and PCR start, mmh won't work well for multi-stream I fear */
826 p_sys->i_pcr_start = 0;
832 return p_input->b_error ? 0 : 1;
835 static int Control( input_thread_t *p_input, int i_query, va_list args )
837 demux_sys_t *p_sys = p_input->p_demux_data;
844 pi64 = (int64_t*)va_arg( args, int64_t * );
845 *pi64 = p_sys->i_pcr - p_sys->i_pcr_start + p_sys->i_start;
848 case DEMUX_GET_LENGTH:
849 pi64 = (int64_t*)va_arg( args, int64_t * );
850 *pi64 = p_sys->i_length;
853 case DEMUX_GET_POSITION:
854 pf = (double*)va_arg( args, double* );
855 if( p_sys->i_length > 0 )
857 *pf = (double)( p_sys->i_pcr - p_sys->i_pcr_start + p_sys->i_start)/
858 (double)(p_sys->i_length);
866 case DEMUX_SET_POSITION:
870 f = (double)va_arg( args, double );
871 time = f * (double)p_sys->i_length / 1000000.0; /* in second */
873 if( p_sys->rtsp && p_sys->i_length > 0 )
875 MediaSubsessionIterator *iter = new MediaSubsessionIterator( *p_sys->ms );
876 MediaSubsession *sub;
879 while( ( sub = iter->next() ) != NULL )
881 p_sys->rtsp->playMediaSubsession( *sub, time );
884 p_sys->i_start = (mtime_t)(f * (double)p_sys->i_length);
885 p_sys->i_pcr_start = 0;
887 for( i = 0; i < p_sys->i_track; i++ )
889 p_sys->track[i]->i_pts = 0;
897 return demux_vaControlDefault( p_input, i_query, args );
901 /*****************************************************************************
903 *****************************************************************************/
904 static void StreamRead( void *p_private, unsigned int i_size, struct timeval pts )
906 live_track_t *tk = (live_track_t*)p_private;
907 input_thread_t *p_input = tk->p_input;
908 demux_sys_t *p_sys = p_input->p_demux_data;
911 mtime_t i_pts = (uint64_t)pts.tv_sec * UI64C(1000000) + (uint64_t)pts.tv_usec;
913 /* XXX Beurk beurk beurk Avoid having negative value XXX */
914 i_pts &= UI64C(0x00ffffffffffffff);
916 if( tk->b_quicktime && tk->p_es == NULL )
918 QuickTimeGenericRTPSource *qtRTPSource = (QuickTimeGenericRTPSource*)tk->rtpSource;
919 QuickTimeGenericRTPSource::QTState &qtState = qtRTPSource->qtState;
920 uint8_t *sdAtom = (uint8_t*)&qtState.sdAtom[4];
922 if( qtState.sdAtomSize < 16 + 32 )
929 tk->fmt.i_codec = VLC_FOURCC( sdAtom[0], sdAtom[1], sdAtom[2], sdAtom[3] );
930 tk->fmt.video.i_width = (sdAtom[28] << 8) | sdAtom[29];
931 tk->fmt.video.i_height = (sdAtom[30] << 8) | sdAtom[31];
933 tk->fmt.i_extra = qtState.sdAtomSize - 16;
934 tk->fmt.p_extra = malloc( tk->fmt.i_extra );
935 memcpy( tk->fmt.p_extra, &sdAtom[12], tk->fmt.i_extra );
937 tk->p_es = es_out_Add( p_input->p_es_out, &tk->fmt );
941 fprintf( stderr, "StreamRead size=%d pts=%lld\n",
943 pts.tv_sec * 1000000LL + pts.tv_usec );
947 msg_Warn( p_input, "buffer overflow" );
949 /* FIXME could i_size be > buffer size ? */
950 p_block = block_New( p_input, i_size );
952 memcpy( p_block->p_buffer, tk->buffer, i_size );
953 //p_block->i_rate = p_input->stream.control.i_rate;
955 if( i_pts != tk->i_pts && !tk->b_muxed )
958 p_block->i_pts = input_ClockGetTS( p_input,
959 p_input->stream.p_selected_program,
962 //fprintf( stderr, "tk -> dpts=%lld\n", i_pts - tk->i_pts );
966 stream_DemuxSend( tk->p_out_muxed, p_block );
970 es_out_Send( p_input->p_es_out, tk->p_es, p_block );
976 /* we have read data */
979 if( i_pts > 0 && !tk->b_muxed )
985 /*****************************************************************************
987 *****************************************************************************/
988 static void StreamClose( void *p_private )
990 live_track_t *tk = (live_track_t*)p_private;
991 input_thread_t *p_input = tk->p_input;
992 demux_sys_t *p_sys = p_input->p_demux_data;
994 fprintf( stderr, "StreamClose\n" );
997 p_input->b_error = VLC_TRUE;
1001 /*****************************************************************************
1003 *****************************************************************************/
1004 static void TaskInterrupt( void *p_private )
1006 input_thread_t *p_input = (input_thread_t*)p_private;
1008 fprintf( stderr, "TaskInterrupt\n" );
1011 p_input->p_demux_data->event = 0xff;