1 /*****************************************************************************
2 * live.cpp : live.com support.
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
5 * $Id: livedotcom.cpp,v 1.5 2003/11/07 22:56:02 gbazin Exp $
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 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." )
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 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 );
78 * - Support PS/TS (need to rework the TS/PS demuxer a lot).
79 * - Support X-QT/X-QUICKTIME generic codec.
80 * - Handle PTS (for now I just use mdate())
82 * - Check memory leak, delete/free.
86 /*****************************************************************************
88 *****************************************************************************/
99 input_thread_t *p_input;
104 FramedSource *readSource;
106 uint8_t buffer[65536];
115 char *p_sdp; /* XXX mallocated */
118 TaskScheduler *scheduler;
119 UsageEnvironment *env ;
123 live_track_t **track; /* XXX mallocated */
130 static ssize_t Read ( input_thread_t *, byte_t *, size_t );
132 static int Demux ( input_thread_t * );
133 static int Control( input_thread_t *, int, va_list );
137 /*****************************************************************************
139 *****************************************************************************/
140 static int AccessOpen( vlc_object_t *p_this )
142 input_thread_t *p_input = (input_thread_t *)p_this;
145 TaskScheduler *scheduler = NULL;
146 UsageEnvironment *env = NULL;
147 RTSPClient *rtsp = NULL;
152 if( p_input->psz_access == NULL || strcasecmp( p_input->psz_access, "rtsp" ) )
154 msg_Warn( p_input, "RTSP access discarded" );
157 if( ( scheduler = BasicTaskScheduler::createNew() ) == NULL )
159 msg_Err( p_input, "BasicTaskScheduler::createNew failed" );
162 if( ( env = BasicUsageEnvironment::createNew(*scheduler) ) == NULL )
165 msg_Err( p_input, "BasicUsageEnvironment::createNew failed" );
168 if( ( rtsp = RTSPClient::createNew(*env, 1/*verbose*/, "VLC Media Player" ) ) == NULL )
172 msg_Err( p_input, "RTSPClient::createNew failed" );
176 psz_url = (char*)malloc( strlen( p_input->psz_name ) + 8 );
177 sprintf( psz_url, "rtsp://%s", p_input->psz_name );
179 p_sys = (access_sys_t*)malloc( sizeof( access_sys_t ) );
180 p_sys->p_sdp = rtsp->describeURL( psz_url );
182 if( p_sys->p_sdp == NULL )
184 msg_Err( p_input, "describeURL failed (%s)", env->getResultMsg() );
193 p_sys->i_sdp = strlen( p_sys->p_sdp );
196 //fprintf( stderr, "sdp=%s\n", p_sys->p_sdp );
201 var_Create( p_input, "rtsp-tcp", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
202 var_Get( p_input, "rtsp-tcp", &val );
204 p_input->p_access_data = p_sys;
207 /* Set exported functions */
208 p_input->pf_read = Read;
209 p_input->pf_seek = NULL;
210 p_input->pf_set_program = input_SetProgram;
211 p_input->pf_set_area = NULL;
212 p_input->p_private = NULL;
214 p_input->psz_demux = "live";
216 /* Finished to set some variable */
217 vlc_mutex_lock( &p_input->stream.stream_lock );
218 /* FIXME that's not true but eg over tcp, server send data too fast */
219 p_input->stream.b_pace_control = val.b_bool;
220 p_input->stream.p_selected_area->i_tell = 0;
221 p_input->stream.b_seekable = 1; /* Hack to display time */
222 p_input->stream.p_selected_area->i_size = 0;
223 p_input->stream.i_method = INPUT_METHOD_NETWORK;
224 vlc_mutex_unlock( &p_input->stream.stream_lock );
226 /* Update default_pts to a suitable value for RTSP access */
227 var_Create( p_input, "rtsp-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
228 var_Get( p_input, "rtsp-caching", &val );
229 p_input->i_pts_delay = val.i_int * 1000;
234 /*****************************************************************************
236 *****************************************************************************/
237 static void AccessClose( vlc_object_t *p_this )
239 input_thread_t *p_input = (input_thread_t *)p_this;
240 access_sys_t *p_sys = p_input->p_access_data;
242 delete[] p_sys->p_sdp;
246 /*****************************************************************************
248 *****************************************************************************/
249 static ssize_t Read ( input_thread_t *p_input, byte_t *p_buffer, size_t i_len )
251 access_sys_t *p_sys = p_input->p_access_data;
252 int i_copy = __MIN( (int)i_len, p_sys->i_sdp - p_sys->i_pos );
256 memcpy( p_buffer, &p_sys->p_sdp[p_sys->i_pos], i_copy );
257 p_sys->i_pos += i_copy;
263 /*****************************************************************************
265 *****************************************************************************/
266 static int DemuxOpen ( vlc_object_t *p_this )
268 input_thread_t *p_input = (input_thread_t *)p_this;
271 MediaSubsessionIterator *iter;
272 MediaSubsession *sub;
282 /* See if it looks like a SDP
283 v, o, s fields are mandatory and in this order */
284 if( stream_Peek( p_input->s, &p_peek, 7 ) < 7 )
286 msg_Err( p_input, "cannot peek" );
289 if( strncmp( (char*)p_peek, "v=0\r\n", 5 ) && strncmp( (char*)p_peek, "v=0\n", 4 ) &&
290 ( p_input->psz_access == NULL || strcasecmp( p_input->psz_access, "rtsp" ) ||
291 p_peek[0] < 'a' || p_peek[0] > 'z' || p_peek[1] != '=' ) )
293 msg_Warn( p_input, "SDP module discarded" );
297 p_input->pf_demux = Demux;
298 p_input->pf_demux_control = Control;
299 p_input->p_demux_data = p_sys = (demux_sys_t*)malloc( sizeof( demux_sys_t ) );
301 p_sys->scheduler = NULL;
308 p_sys->i_pcr_start = 0;
310 /* Gather the complete sdp file */
313 p_sdp = (uint8_t*)malloc( i_sdp_max );
316 int i_read = stream_Read( p_input->s, &p_sdp[i_sdp], i_sdp_max - i_sdp - 1 );
320 msg_Err( p_input, "failed to read SDP" );
327 if( i_read < i_sdp_max - i_sdp - 1 )
334 p_sdp = (uint8_t*)realloc( p_sdp, i_sdp_max );
336 p_sys->p_sdp = (char*)p_sdp;
338 fprintf( stderr, "sdp=%s\n", p_sys->p_sdp );
340 if( ( p_sys->scheduler = BasicTaskScheduler::createNew() ) == NULL )
342 msg_Err( p_input, "BasicTaskScheduler::createNew failed" );
345 if( ( p_sys->env = BasicUsageEnvironment::createNew(*p_sys->scheduler) ) == NULL )
347 msg_Err( p_input, "BasicUsageEnvironment::createNew failed" );
350 if( p_input->psz_access != NULL && !strcasecmp( p_input->psz_access, "rtsp" ) )
355 if( ( p_sys->rtsp = RTSPClient::createNew(*p_sys->env, 1/*verbose*/, "VLC Media Player" ) ) == NULL )
357 msg_Err( p_input, "RTSPClient::createNew failed (%s)", p_sys->env->getResultMsg() );
360 psz_url = (char*)malloc( strlen( p_input->psz_name ) + 8 );
361 sprintf( psz_url, "rtsp://%s", p_input->psz_name );
363 psz_options = p_sys->rtsp->sendOptionsCmd( psz_url );
364 /* FIXME psz_options -> delete or free */
367 if( ( p_sys->ms = MediaSession::createNew(*p_sys->env, p_sys->p_sdp ) ) == NULL )
369 msg_Err( p_input, "MediaSession::createNew failed" );
373 var_Create( p_input, "rtsp-tcp", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
374 var_Get( p_input, "rtsp-tcp", &val );
376 /* Initialise each media subsession */
377 iter = new MediaSubsessionIterator( *p_sys->ms );
378 while( ( sub = iter->next() ) != NULL )
380 unsigned int i_buffer = 0;
382 /* Value taken from mplayer */
383 if( !strcmp( sub->mediumName(), "audio" ) )
387 else if( !strcmp( sub->mediumName(), "video" ) )
396 if( !sub->initiate() )
398 msg_Warn( p_input, "RTP subsession '%s/%s' failed(%s)", sub->mediumName(), sub->codecName(), p_sys->env->getResultMsg() );
402 int fd = sub->rtpSource()->RTPgs()->socketNum();
404 msg_Warn( p_input, "RTP subsession '%s/%s'", sub->mediumName(), sub->codecName() );
406 /* Increase the buffer size */
407 increaseReceiveBufferTo( *p_sys->env, fd, i_buffer );
408 /* Issue the SETUP */
411 p_sys->rtsp->setupMediaSubsession( *sub, False, val.b_bool ? True : False );
419 if( !p_sys->rtsp->playMediaSession( *p_sys->ms ) )
421 msg_Err( p_input, "PLAY failed %s", p_sys->env->getResultMsg() );
426 /* Create all es struct */
428 while( ( sub = iter->next() ) != NULL )
432 if( sub->readSource() == NULL )
437 tk = (live_track_t*)malloc( sizeof( live_track_t ) );
438 tk->p_input = p_input;
442 /* Value taken from mplayer */
443 if( !strcmp( sub->mediumName(), "audio" ) )
445 es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC( 'u', 'n', 'd', 'f' ) );
446 tk->fmt.audio.i_channels = sub->numChannels();
447 tk->fmt.audio.i_samplerate = sub->rtpSource()->timestampFrequency();
449 if( !strcmp( sub->codecName(), "MPA" ) ||
450 !strcmp( sub->codecName(), "MPA-ROBUST" ) ||
451 !strcmp( sub->codecName(), "X-MP3-DRAFT-00" ) )
453 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
454 tk->fmt.audio.i_samplerate = 0;
456 else if( !strcmp( sub->codecName(), "AC3" ) )
458 tk->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
459 tk->fmt.audio.i_samplerate = 0;
461 else if( !strcmp( sub->codecName(), "L16" ) )
463 tk->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
464 tk->fmt.audio.i_bitspersample = 16;
466 else if( !strcmp( sub->codecName(), "L8" ) )
468 tk->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
469 tk->fmt.audio.i_bitspersample = 8;
471 else if( !strcmp( sub->codecName(), "PCMU" ) )
473 tk->fmt.i_codec = VLC_FOURCC( 'u', 'l', 'a', 'w' );
475 else if( !strcmp( sub->codecName(), "PCMA" ) )
477 tk->fmt.i_codec = VLC_FOURCC( 'a', 'l', 'a', 'w' );
479 else if( !strcmp( sub->codecName(), "MP4A-LATM" ) )
481 unsigned int i_extra;
484 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
486 if( ( p_extra = parseStreamMuxConfigStr( sub->fmtp_config(), i_extra ) ) )
488 tk->fmt.i_extra_type = ES_EXTRA_TYPE_WAVEFORMATEX;
489 tk->fmt.i_extra = i_extra;
490 tk->fmt.p_extra = malloc( sizeof( i_extra ) );
491 memcpy( tk->fmt.p_extra, p_extra, i_extra );
495 else if( !strcmp( sub->codecName(), "MPEG4-GENERIC" ) )
497 unsigned int i_extra;
500 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
502 if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(), i_extra ) ) )
504 tk->fmt.i_extra_type = ES_EXTRA_TYPE_WAVEFORMATEX;
505 tk->fmt.i_extra = i_extra;
506 tk->fmt.p_extra = malloc( i_extra );
507 memcpy( tk->fmt.p_extra, p_extra, i_extra );
512 else if( !strcmp( sub->mediumName(), "video" ) )
514 es_format_Init( &tk->fmt, VIDEO_ES, VLC_FOURCC( 'u', 'n', 'd', 'f' ) );
515 if( !strcmp( sub->codecName(), "MPV" ) )
517 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'v' );
519 else if( !strcmp( sub->codecName(), "H263" ) ||
520 !strcmp( sub->codecName(), "H263-1998" ) )
522 tk->fmt.i_codec = VLC_FOURCC( 'h', '2', '6', '3' );
524 else if( !strcmp( sub->codecName(), "H261" ) )
526 tk->fmt.i_codec = VLC_FOURCC( 'h', '2', '6', '1' );
528 else if( !strcmp( sub->codecName(), "JPEG" ) )
530 tk->fmt.i_codec = VLC_FOURCC( 'J', 'P', 'E', 'G' );
532 else if( !strcmp( sub->codecName(), "MP4V-ES" ) )
534 unsigned int i_extra;
537 tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' );
539 if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(), i_extra ) ) )
541 tk->fmt.i_extra_type = ES_EXTRA_TYPE_BITMAPINFOHEADER;
542 tk->fmt.i_extra = i_extra;
543 tk->fmt.p_extra = malloc( i_extra );
544 memcpy( tk->fmt.p_extra, p_extra, i_extra );
550 if( tk->fmt.i_codec != VLC_FOURCC( 'u', 'n', 'd', 'f' ) )
552 tk->p_es = es_out_Add( p_input->p_es_out, &tk->fmt );
557 TAB_APPEND( p_sys->i_track, (void**)p_sys->track, (void*)tk );
558 tk->readSource = sub->readSource();
574 Medium::close( p_sys->ms );
578 Medium::close( p_sys->rtsp );
584 if( p_sys->scheduler )
586 delete p_sys->scheduler;
590 free( p_sys->p_sdp );
598 /*****************************************************************************
600 *****************************************************************************/
601 static void DemuxClose( vlc_object_t *p_this )
603 input_thread_t *p_input = (input_thread_t *)p_this;
604 demux_sys_t *p_sys = p_input->p_demux_data;
607 for( i = 0; i < p_sys->i_track; i++ )
609 live_track_t *tk = p_sys->track[i];
615 free( p_sys->track );
618 if( p_sys->rtsp && p_sys->ms )
621 p_sys->rtsp->teardownMediaSession( *p_sys->ms );
623 Medium::close( p_sys->ms );
626 Medium::close( p_sys->rtsp );
633 if( p_sys->scheduler )
635 delete p_sys->scheduler;
639 free( p_sys->p_sdp );
645 static void StreamRead( void *p_private, unsigned int i_size, struct timeval pts );
646 static void StreamClose( void *p_private );
647 static void TaskInterrupt( void *p_private );
649 /*****************************************************************************
651 *****************************************************************************/
652 static int Demux ( input_thread_t *p_input )
654 demux_sys_t *p_sys = p_input->p_demux_data;
660 for( i = 0; i < p_sys->i_track; i++ )
662 live_track_t *tk = p_sys->track[i];
668 else if( tk->i_pts != 0 && i_pcr > tk->i_pts )
673 if( i_pcr != p_sys->i_pcr )
675 input_ClockManageRef( p_input,
676 p_input->stream.p_selected_program,
678 p_sys->i_pcr = i_pcr;
679 if( p_sys->i_pcr_start <= 0 || p_sys->i_pcr_start > i_pcr )
681 p_sys->i_pcr_start = i_pcr;
685 /* First warm we want to read data */
687 for( i = 0; i < p_sys->i_track; i++ )
689 live_track_t *tk = p_sys->track[i];
691 if( tk->waiting == 0 )
694 tk->readSource->getNextFrame( tk->buffer, 65536,
699 /* Create a task that will be called if we wait more than 300ms */
700 task = p_sys->scheduler->scheduleDelayedTask( 300000, TaskInterrupt, p_input );
703 p_sys->scheduler->doEventLoop( &p_sys->event );
705 /* remove the task */
706 p_sys->scheduler->unscheduleDelayedTask( task );
708 return p_input->b_error ? 0 : 1;
711 static int Control( input_thread_t *p_input, int i_query, va_list args )
713 demux_sys_t *p_sys = p_input->p_demux_data;
719 pi64 = (int64_t*)va_arg( args, int64_t * );
720 *pi64 = p_sys->i_pcr - p_sys->i_pcr_start;
724 return demux_vaControlDefault( p_input, i_query, args );
728 /*****************************************************************************
730 *****************************************************************************/
731 static void StreamRead( void *p_private, unsigned int i_size, struct timeval pts )
733 live_track_t *tk = (live_track_t*)p_private;
734 input_thread_t *p_input = tk->p_input;
735 demux_sys_t *p_sys = p_input->p_demux_data;
737 data_packet_t *p_data;
739 mtime_t i_pts = (mtime_t)pts.tv_sec * 1000000LL + (mtime_t)pts.tv_usec;
742 fprintf( stderr, "StreamRead size=%d pts=%lld\n",
744 pts.tv_sec * 1000000LL + pts.tv_usec );
747 if( ( p_pes = input_NewPES( p_input->p_method_data ) ) == NULL )
751 /* FIXME could i_size be > buffer size ? */
752 p_data = input_NewPacket( p_input->p_method_data, i_size );
754 memcpy( p_data->p_payload_start, tk->buffer, i_size );
755 p_data->p_payload_end = p_data->p_payload_start + i_size;
757 p_pes->p_first = p_pes->p_last = p_data;
758 p_pes->i_nb_data = 1;
759 p_pes->i_pes_size = i_size;
760 p_pes->i_rate = p_input->stream.control.i_rate;
762 if( i_pts != tk->i_pts )
765 p_pes->i_pts = input_ClockGetTS( p_input,
766 p_input->stream.p_selected_program,
774 //fprintf( stderr, "tk -> dpts=%lld\n", i_pts - tk->i_pts );
776 es_out_Send( p_input->p_es_out, tk->p_es, p_pes );
781 /* we have read data */
787 /*****************************************************************************
789 *****************************************************************************/
790 static void StreamClose( void *p_private )
792 live_track_t *tk = (live_track_t*)p_private;
793 input_thread_t *p_input = tk->p_input;
794 demux_sys_t *p_sys = p_input->p_demux_data;
796 fprintf( stderr, "StreamClose\n" );
799 p_input->b_error = VLC_TRUE;
803 /*****************************************************************************
805 *****************************************************************************/
806 static void TaskInterrupt( void *p_private )
808 input_thread_t *p_input = (input_thread_t*)p_private;
810 fprintf( stderr, "TaskInterrupt\n" );
813 p_input->p_demux_data->event = 0xff;