]> git.sesse.net Git - vlc/blobdiff - modules/access/live555.cpp
live555: remove dead fallback for speex
[vlc] / modules / access / live555.cpp
index 2d9246ae8999989a345e286050e523299170e0e6..d49fc6d3f2126b96236ce350f4664554967aa28e 100644 (file)
@@ -52,7 +52,7 @@
 #include <assert.h>
 
 
-#if defined( WIN32 )
+#if defined( _WIN32 )
 #   include <winsock2.h>
 #endif
 
@@ -61,6 +61,7 @@
 #include <GroupsockHelper.hh>
 #include <liveMedia.hh>
 #include <liveMedia_version.hh>
+#include <Base64.hh>
 
 extern "C" {
 #include "../access/mms/asf.h"  /* Who said ugly ? */
@@ -90,6 +91,11 @@ static void Close( vlc_object_t * );
 #define PASS_TEXT N_("RTSP password")
 #define PASS_LONGTEXT N_("Sets the password for the connection, " \
     "if no username or password are set in the url.")
+#define FRAME_BUFFER_SIZE_TEXT N_("RTSP frame buffer size")
+#define FRAME_BUFFER_SIZE_LONGTEXT N_("RTSP start frame buffer size of the video " \
+    "track, can be increased in case of broken pictures due " \
+    "to too small buffer.")
+#define DEFAULT_FRAME_BUFFER_SIZE 100000
 
 vlc_module_begin ()
     set_description( N_("RTP/RTSP/SDP demuxer (using Live555)" ) )
@@ -135,7 +141,9 @@ vlc_module_begin ()
             change_safe()
         add_password( "rtsp-pwd", NULL, PASS_TEXT,
                       PASS_LONGTEXT, true )
-            change_safe()
+        add_integer( "rtsp-frame-buffer-size", DEFAULT_FRAME_BUFFER_SIZE,
+                     FRAME_BUFFER_SIZE_TEXT, FRAME_BUFFER_SIZE_LONGTEXT,
+                     true )
 vlc_module_end ()
 
 
@@ -235,7 +243,11 @@ public:
                    char const* applicationName, portNumBits tunnelOverHTTPPortNum,
                    demux_sys_t *p_sys) :
                    RTSPClient( env, rtspURL, verbosityLevel, applicationName,
-                   tunnelOverHTTPPortNum )
+                   tunnelOverHTTPPortNum
+#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1373932800
+                   , -1
+#endif
+                   )
     {
         this->p_sys = p_sys;
     }
@@ -261,6 +273,8 @@ static void* TimeoutPrevention( void * );
 
 static unsigned char* parseH264ConfigStr( char const* configStr,
                                           unsigned int& configSize );
+static unsigned char* parseVorbisConfigStr( char const* configStr,
+                                            unsigned int& configSize );
 
 /*****************************************************************************
  * DemuxOpen:
@@ -293,7 +307,7 @@ static int  Open ( vlc_object_t *p_this )
     p_demux->p_sys     = p_sys = (demux_sys_t*)calloc( 1, sizeof( demux_sys_t ) );
     if( !p_sys ) return VLC_ENOMEM;
 
-    msg_Dbg( p_demux, "version "LIVEMEDIA_LIBRARY_VERSION_STRING );
+    msg_Dbg( p_demux, "version " LIVEMEDIA_LIBRARY_VERSION_STRING );
 
     TAB_INIT( p_sys->i_track, p_sys->track );
     p_sys->f_npt = 0.;
@@ -520,7 +534,7 @@ static void continueAfterOPTIONS( RTSPClient* client, int result_code,
       // If OPTIONS fails, assume GET_PARAMETER is not supported but
       // still continue on with the stream.  Some servers (foscam)
       // return 501/not implemented for OPTIONS.
-      result_code != 0
+      result_code == 0
       && result_string != NULL
       && strstr( result_string, "GET_PARAMETER" ) != NULL;
     client->sendDescribeCommand( continueAfterDESCRIBE );
@@ -577,7 +591,7 @@ createnew:
 
     p_sys->rtsp = new RTSPClientVlc( *p_sys->env, psz_url,
                                      var_InheritInteger( p_demux, "verbose" ) > 1 ? 1 : 0,
-                                     "LibVLC/"VERSION, i_http_port, p_sys );
+                                     "LibVLC/" VERSION, i_http_port, p_sys );
     if( !p_sys->rtsp )
     {
         msg_Err( p_demux, "RTSPClient::createNew failed (%s)",
@@ -668,13 +682,17 @@ static int SessionsSetup( demux_t *p_demux )
     bool           b_rtsp_tcp;
     int            i_client_port;
     int            i_return = VLC_SUCCESS;
-    unsigned int   i_buffer = 0;
+    unsigned int   i_receive_buffer = 0;
+    int            i_frame_buffer = DEFAULT_FRAME_BUFFER_SIZE;
     unsigned const thresh = 200000; /* RTP reorder threshold .2 second (default .1) */
+    const char     *p_sess_lang = NULL;
+    const char     *p_lang;
 
     b_rtsp_tcp    = var_CreateGetBool( p_demux, "rtsp-tcp" ) ||
                     var_GetBool( p_demux, "rtsp-http" );
     i_client_port = var_InheritInteger( p_demux, "rtp-client-port" );
 
+
     /* Create the session from the SDP */
     if( !( p_sys->ms = MediaSession::createNew( *p_sys->env, p_sys->p_sdp ) ) )
     {
@@ -683,6 +701,20 @@ static int SessionsSetup( demux_t *p_demux )
         return VLC_EGENERIC;
     }
 
+    if( strcmp( p_sys->p_sdp, "m=" ) != 0 )
+    {
+        const char *p_sess_attr_end;
+
+        p_sess_attr_end = strstr( p_sys->p_sdp, "\nm=" );
+        if( !p_sess_attr_end )
+            p_sess_attr_end = strstr( p_sys->p_sdp, "\rm=" );
+
+        p_sess_lang = p_sess_attr_end ? strstr( p_sys->p_sdp, "a=lang:" ) : NULL;
+        if( p_sess_lang &&
+            p_sess_lang - p_sys->p_sdp > p_sess_attr_end - p_sys->p_sdp )
+            p_sess_lang = NULL;
+    }
+
     /* Initialise each media subsession */
     iter = new MediaSubsessionIterator( *p_sys->ms );
     while( ( sub = iter->next() ) != NULL )
@@ -698,9 +730,14 @@ static int SessionsSetup( demux_t *p_demux )
 
         /* Value taken from mplayer */
         if( !strcmp( sub->mediumName(), "audio" ) )
-            i_buffer = 100000;
+            i_receive_buffer = 100000;
         else if( !strcmp( sub->mediumName(), "video" ) )
-            i_buffer = 2000000;
+        {
+            int i_var_buf_size = var_InheritInteger( p_demux, "rtsp-frame-buffer-size" );
+            if( i_var_buf_size > 0 )
+                i_frame_buffer = i_var_buf_size;
+            i_receive_buffer = 2000000;
+        }
         else if( !strcmp( sub->mediumName(), "text" ) )
             ;
         else continue;
@@ -736,8 +773,8 @@ static int SessionsSetup( demux_t *p_demux )
                 int fd = sub->rtpSource()->RTPgs()->socketNum();
 
                 /* Increase the buffer size */
-                if( i_buffer > 0 )
-                    increaseReceiveBufferTo( *p_sys->env, fd, i_buffer );
+                if( i_receive_buffer > 0 )
+                    increaseReceiveBufferTo( *p_sys->env, fd, i_receive_buffer );
 
                 /* Increase the RTP reorder timebuffer just a bit */
                 sub->rtpSource()->setPacketReorderingThresholdTime(thresh);
@@ -802,8 +839,9 @@ static int SessionsSetup( demux_t *p_demux )
             tk->i_pts       = VLC_TS_INVALID;
             tk->f_npt       = 0.;
             tk->b_selected  = true;
-            tk->i_buffer    = 65536;
-            tk->p_buffer    = (uint8_t *)malloc( 65536 );
+            tk->i_buffer    = i_frame_buffer;
+            tk->p_buffer    = (uint8_t *)malloc( i_frame_buffer );
+
             if( !tk->p_buffer )
             {
                 free( tk );
@@ -938,13 +976,24 @@ static int SessionsSetup( demux_t *p_demux )
                 else if( !strcmp( sub->codecName(), "SPEEX" ) )
                 {
                     tk->fmt.i_codec = VLC_FOURCC( 's', 'p', 'x', 'r' );
-                    if ( sub->rtpTimestampFrequency() )
-                        tk->fmt.audio.i_rate = sub->rtpTimestampFrequency();
-                    else
+                }
+                else if( !strcmp( sub->codecName(), "VORBIS" ) )
+                {
+                    tk->fmt.i_codec = VLC_CODEC_VORBIS;
+                    unsigned int i_extra;
+                    unsigned char *p_extra;
+                    if( ( p_extra=parseVorbisConfigStr( sub->fmtp_config(),
+                                                        i_extra ) ) )
                     {
-                        msg_Warn( p_demux,"Using 8kHz as default sample rate." );
-                        tk->fmt.audio.i_rate = 8000;
+                        tk->fmt.i_extra = i_extra;
+                        tk->fmt.p_extra = p_extra;
                     }
+                    else
+                        msg_Warn( p_demux,"Missing or unsupported vorbis header." );
+                }
+                else if( !strcmp( sub->codecName(), "OPUS" ) )
+                {
+                    tk->fmt.i_codec = VLC_CODEC_OPUS;
                 }
             }
             else if( !strcmp( sub->mediumName(), "video" ) )
@@ -983,6 +1032,40 @@ static int SessionsSetup( demux_t *p_demux )
                         delete[] p_extra;
                     }
                 }
+#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1393372800 // 2014.02.26
+                else if( !strcmp( sub->codecName(), "H265" ) )
+                {
+                   unsigned int i_extra1 = 0, i_extra2 = 0, i_extra3 = 0, i_extraTot;
+                    uint8_t      *p_extra1 = NULL, *p_extra2 = NULL, *p_extra3 = NULL;
+
+                    tk->fmt.i_codec = VLC_CODEC_HEVC;
+                    tk->fmt.b_packetized = false;
+
+                    p_extra1 = parseH264ConfigStr( sub->fmtp_spropvps(), i_extra1 );
+                    p_extra2 = parseH264ConfigStr( sub->fmtp_spropsps(), i_extra2 );
+                    p_extra3 = parseH264ConfigStr( sub->fmtp_sproppps(), i_extra3 );
+                   i_extraTot = i_extra1 + i_extra2 + i_extra3;
+                   if( i_extraTot > 0 )
+                    {
+                        tk->fmt.i_extra = i_extraTot;
+                        tk->fmt.p_extra = xmalloc( i_extraTot );
+                       if( p_extra1 )
+                       {
+                            memcpy( tk->fmt.p_extra, p_extra1, i_extra1 );
+                       }
+                       if( p_extra2 )
+                       {
+                         memcpy( ((char*)tk->fmt.p_extra)+i_extra1, p_extra2, i_extra2 );
+                       }
+                       if( p_extra3 )
+                       {
+                         memcpy( ((char*)tk->fmt.p_extra)+i_extra1+i_extra2, p_extra3, i_extra3 );
+                       }
+
+                        delete[] p_extra1; delete[] p_extra2; delete[] p_extra3;
+                    }
+                }
+#endif
                 else if( !strcmp( sub->codecName(), "JPEG" ) )
                 {
                     tk->fmt.i_codec = VLC_CODEC_MJPG;
@@ -1037,6 +1120,24 @@ static int SessionsSetup( demux_t *p_demux )
                     tk->p_out_muxed = stream_DemuxNew( p_demux, "rawdv",
                                                        p_demux->out );
                 }
+                else if( !strcmp( sub->codecName(), "VP8" ) )
+                {
+                    tk->fmt.i_codec = VLC_CODEC_VP8;
+                }
+                else if( !strcmp( sub->codecName(), "THEORA" ) )
+                {
+                    tk->fmt.i_codec = VLC_CODEC_THEORA;
+                    unsigned int i_extra;
+                    unsigned char *p_extra;
+                    if( ( p_extra=parseVorbisConfigStr( sub->fmtp_config(),
+                                                        i_extra ) ) )
+                    {
+                        tk->fmt.i_extra = i_extra;
+                        tk->fmt.p_extra = p_extra;
+                    }
+                    else
+                        msg_Warn( p_demux,"Missing or unsupported theora header." );
+                }
             }
             else if( !strcmp( sub->mediumName(), "text" ) )
             {
@@ -1048,6 +1149,19 @@ static int SessionsSetup( demux_t *p_demux )
                 }
             }
 
+            /* Try and parse a=lang: attribute */
+            p_lang = strstr( sub->savedSDPLines(), "a=lang:" );
+            if( !p_lang )
+                p_lang = p_sess_lang;
+
+            if( p_lang )
+            {
+                unsigned i_lang_len;
+                p_lang += 7;
+                i_lang_len = strcspn( p_lang, " \r\n" );
+                tk->fmt.psz_language = strndup( p_lang, i_lang_len );
+            }
+
             if( !tk->b_quicktime && !tk->b_muxed && !tk->b_asf )
             {
                 tk->p_es = es_out_Add( p_demux->out, &tk->fmt );
@@ -1115,7 +1229,8 @@ static int Play( demux_t *p_demux )
             p_sys->i_timeout = 60; /* default value from RFC2326 */
 
         /* start timeout-thread only if GET_PARAMETER is supported by the server */
-        if( !p_sys->p_timeout && p_sys->b_get_param )
+        /* or start it if wmserver dialect, since they don't report that GET_PARAMETER is supported correctly */
+        if( !p_sys->p_timeout && ( p_sys->b_get_param || var_InheritBool( p_demux, "rtsp-wmserver" ) ) )
         {
             msg_Dbg( p_demux, "We have a timeout of %d seconds",  p_sys->i_timeout );
             p_sys->p_timeout = (timeout_thread_t *)malloc( sizeof(timeout_thread_t) );
@@ -1158,7 +1273,6 @@ static int Demux( demux_t *p_demux )
     TaskToken      task;
 
     bool            b_send_pcr = true;
-    int64_t         i_pcr = 0;
     int             i;
 
     /* Check if we need to send the server a Keep-A-Live signal */
@@ -1177,7 +1291,7 @@ static int Demux( demux_t *p_demux )
         {
             bool b;
             es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
-            if( !b && tk->b_selected )
+            if( !b && tk->b_selected && p_sys->rtsp )
             {
                 tk->b_selected = false;
                 p_sys->rtsp->sendTeardownCommand( *tk->sub, NULL );
@@ -1213,16 +1327,6 @@ static int Demux( demux_t *p_demux )
 
         if( tk->b_asf || tk->b_muxed )
             b_send_pcr = false;
-#if 0
-        if( i_pcr == 0 )
-        {
-            i_pcr = tk->i_pts;
-        }
-        else if( tk->i_pts != 0 && i_pcr > tk->i_pts )
-        {
-            i_pcr = tk->i_pts ;
-        }
-#endif
     }
     if( p_sys->i_pcr > 0 )
     {
@@ -1269,7 +1373,6 @@ static int Demux( demux_t *p_demux )
             tk->f_npt = 0.;
             p_sys->i_pcr = 0;
             p_sys->f_npt = 0.;
-            i_pcr = 0;
         }
     }
 
@@ -1399,7 +1502,6 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
                 }
                 p_sys->i_pcr = 0;
 
-                /* Retrieve RTP-Info values */
                 for( i = 0; i < p_sys->i_track; i++ )
                 {
                     p_sys->track[i]->b_rtcp_sync = false;
@@ -1766,7 +1868,7 @@ static void StreamRead( void *p_private, unsigned int i_size,
         QuickTimeGenericRTPSource::QTState &qtState = qtRTPSource->qtState;
         uint8_t *sdAtom = (uint8_t*)&qtState.sdAtom[4];
 
-        /* Get codec informations from the quicktime atoms :
+        /* Get codec information from the quicktime atoms :
          * http://developer.apple.com/quicktime/icefloe/dispatch026.html */
         if( tk->fmt.i_cat == VIDEO_ES ) {
             if( qtState.sdAtomSize < 16 + 32 )
@@ -1878,10 +1980,12 @@ static void StreamRead( void *p_private, unsigned int i_size,
         if( tk->sub->rtpSource()->curPacketMarkerBit() )
             p_block->i_flags |= BLOCK_FLAG_END_OF_FRAME;
     }
-    else if( tk->fmt.i_codec == VLC_CODEC_H264 )
+    else if( tk->fmt.i_codec == VLC_CODEC_H264 || tk->fmt.i_codec == VLC_CODEC_HEVC )
     {
-        if( (tk->p_buffer[0] & 0x1f) >= 24 )
+        if( tk->fmt.i_codec == VLC_CODEC_H264 && (tk->p_buffer[0] & 0x1f) >= 24 )
             msg_Warn( p_demux, "unsupported NAL type for H264" );
+        else if( tk->fmt.i_codec == VLC_CODEC_HEVC && ((tk->p_buffer[0] & 0x7e)>>1) >= 48 )
+            msg_Warn( p_demux, "unsupported NAL type for H265" );
 
         /* Normal NAL type */
         p_block = block_Alloc( i_size + 4 );
@@ -1909,7 +2013,7 @@ static void StreamRead( void *p_private, unsigned int i_size,
     }
 
     /* Update our global npt value */
-    if( tk->f_npt > 0 && tk->f_npt > p_sys->f_npt &&
+    if( tk->f_npt > 0 &&
         ( tk->f_npt < p_sys->f_npt_length || p_sys->f_npt_length <= 0 ) )
         p_sys->f_npt = tk->f_npt;
 
@@ -2111,3 +2215,30 @@ static unsigned char* parseH264ConfigStr( char const* configStr,
     free( dup );
     return cfg;
 }
+
+static uint8_t *parseVorbisConfigStr( char const* configStr,
+                                      unsigned int& configSize )
+{
+    configSize = 0;
+    if( configStr == NULL || *configStr == '\0' )
+        return NULL;
+#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1332115200 // 2012.03.20
+    unsigned char *p_cfg = base64Decode( configStr, configSize );
+#else
+    char* configStr_dup = strdup( configStr );
+    unsigned char *p_cfg = base64Decode( configStr_dup, configSize );
+    free( configStr_dup );
+#endif
+    uint8_t *p_extra = NULL;
+    /* skip header count, ident number and length (cf. RFC 5215) */
+    const unsigned int headerSkip = 9;
+    if( configSize > headerSkip && ((uint8_t*)p_cfg)[3] == 1 )
+    {
+        configSize -= headerSkip;
+        p_extra = (uint8_t*)xmalloc( configSize );
+        memcpy( p_extra, p_cfg+headerSkip, configSize );
+    }
+    delete[] p_cfg;
+    return p_extra;
+}
+