Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
fa55e4cf
Commit
fa55e4cf
authored
Nov 06, 2004
by
Clément Stenac
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
rewrite of the SAP parser
parent
f9d5e2ba
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
675 additions
and
967 deletions
+675
-967
modules/misc/sap.c
modules/misc/sap.c
+675
-967
No files found.
modules/misc/sap.c
View file @
fa55e4cf
/*****************************************************************************
* sap.c : SAP interface module
*****************************************************************************
* Copyright (C) 200
1
VideoLAN
* Copyright (C) 200
4
VideoLAN
* $Id$
*
* Authors: Arnaud Schauly <gitan@via.ecp.fr>
* Clment Stenac <zorglub@via.ecp.fr>
* Damien Lucas <nitrox@videolan.org>
* Laurent Aimar <fenrir@via.ecp.fr>
* Authors: Clment Stenac <zorglub@videolan.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -25,16 +22,18 @@
*****************************************************************************/
/*****************************************************************************
*
Preamble
*
Includes
*****************************************************************************/
#include <stdlib.h>
/* malloc(), free() */
#include <vlc/vlc.h>
#include <vlc/intf.h>
#include <vlc/input.h>
#include "network.h"
#include <errno.h>
/* ENOMEM */
#include <ctype.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
...
...
@@ -43,39 +42,19 @@
# include <sys/time.h>
#endif
#ifdef WIN32
# include <winsock2.h>
# include <ws2tcpip.h>
# ifndef IN_MULTICAST
# define IN_MULTICAST(a) IN_CLASSD(a)
# endif
#else
# include <sys/socket.h>
# include <netinet/in.h>
# if HAVE_ARPA_INET_H
# include <arpa/inet.h>
# elif defined( SYS_BEOS )
# include <net/netdb.h>
# endif
#endif
#ifdef UNDER_CE
# define close(a) CloseHandle(a)
#elif defined( WIN32 )
# define close(a) closesocket(a)
#endif
#include "network.h"
#ifdef HAVE_ZLIB_H
# include <zlib.h>
#endif
/************************************************************************
* Macros and definitions
************************************************************************/
#define MAX_LINE_LENGTH 256
/* SAP is always on that port */
#define
HELLO
_PORT 9875
#define
HELLO_GROUP
"224.2.127.254"
#define
SAP
_PORT 9875
#define
SAP_V4_ADDRESS
"224.2.127.254"
#define ADD_SESSION 1
#define IPV6_ADDR_1 "FF0"
/* Scope is inserted between them */
...
...
@@ -102,13 +81,14 @@
"is received." )
#define SAP_PARSE_TEXT N_( "Try to parse the SAP" )
#define SAP_PARSE_LONGTEXT N_( \
"When SAP can it will try to parse the SAP.
Normal behavior is
" \
"t
o have livedotcom parse the announce.
" )
"When SAP can it will try to parse the SAP.
If you don't select
" \
"t
his, all announces will be parsed by the livedotcom module
" )
static
int
Open
(
vlc_object_t
*
);
static
void
Close
(
vlc_object_t
*
);
static
int
OpenSDP
(
vlc_object_t
*
);
static
void
CloseSDP
(
vlc_object_t
*
);
/* Callbacks */
static
int
Open
(
vlc_object_t
*
);
static
void
Close
(
vlc_object_t
*
);
static
int
OpenDemux
(
vlc_object_t
*
);
static
void
CloseDemux
(
vlc_object_t
*
);
vlc_module_begin
();
set_description
(
_
(
"SAP interface"
)
);
...
...
@@ -128,63 +108,47 @@ vlc_module_begin();
set_capability
(
"interface"
,
0
);
set_callbacks
(
Open
,
Close
);
add_submodule
();
/* TODO FIXME
* This submodule is temporary and has a very high duplicate code rate
* This needs to be removed when SDP UDP parsing is fixed in liveMedia
*/
set_description
(
_
(
"SDP file parser (UDP only)"
)
);
set_description
(
_
(
"SDP file parser for UDP"
)
);
add_shortcut
(
"sdp"
);
set_capability
(
"demux2"
,
51
);
set_callbacks
(
OpenSDP
,
CloseSDP
);
set_callbacks
(
OpenDemux
,
CloseDemux
);
vlc_module_end
();
/*****************************************************************************
* Local
prototyp
es
* Local
structur
es
*****************************************************************************/
static
void
Run
(
intf_thread_t
*
p_intf
);
static
ssize_t
NetRead
(
intf_thread_t
*
,
int
fd
[
2
],
uint8_t
*
,
int
);
static
int
Demux
(
demux_t
*
p_demux
);
static
int
Control
(
demux_t
*
,
int
,
va_list
);
typedef
struct
sdp_t
sdp_t
;
typedef
struct
attribute_t
attribute_t
;
typedef
struct
sap_announce_t
sap_announce_t
;
typedef
struct
media_descr_t
media_descr_t
;
typedef
struct
sess_descr_t
sess_descr_t
;
typedef
struct
attr_descr_t
attr_descr_t
;
/* The structure that contains sdp information */
struct
sdp_t
{
char
*
psz_sdp
;
static
void
sess_toitem
(
intf_thread_t
*
,
sess_descr_t
*
);
/* s= field */
char
*
psz_sessionname
;
static
sess_descr_t
*
parse_sdp
(
vlc_object_t
*
,
char
*
)
;
static
void
free_sd
(
sess_descr_t
*
);
/* Raw m= and c= fields */
char
*
psz_connection
;
char
*
psz_media
;
/* Detect multicast addresses
*/
static
int
ismult
(
char
*
)
;
/* "computed" URI
*/
char
*
psz_uri
;
/* The struct that contains sdp information */
struct
sess_descr_t
{
int
i_version
;
char
*
psz_sessionname
;
char
*
psz_connection
;
char
*
psz_sdp
;
int
i_in
;
/* IP version */
int
i_media
;
media_descr_t
**
pp_media
;
int
i_attributes
;
attr_descr_t
**
pp_attributes
;
};
/* All this information is not useful yet. */
struct
media_descr_t
{
char
*
psz_medianame
;
char
*
psz_mediaconnection
;
int
i_attributes
;
attribute_t
**
pp_attributes
;
};
struct
attr
_descr
_t
struct
attr
ibute
_t
{
char
*
psz_field
;
char
*
psz_value
;
...
...
@@ -193,71 +157,65 @@ struct attr_descr_t
struct
sap_announce_t
{
mtime_t
i_last
;
int
i_id
;
char
*
psz_name
;
char
*
psz_uri
;
uint16_t
i_hash
;
uint32_t
i_source
[
4
];
/* SAP annnounces must only contain one SDP */
sdp_t
*
p_sdp
;
playlist_item_t
*
p_item
;
};
struct
intf_sys_t
{
/* IPV4 and IPV6 */
int
fd
[
2
];
/* Socket descriptors */
int
i_fd
;
int
*
pi_fd
;
/* playlist
group
*/
int
i_group
;
/* playlist
node
*/
playlist_item_t
*
p_node
;
/* Table of announces */
int
i_announces
;
struct
sap_announce_t
**
pp_announces
;
/* Modes */
vlc_bool_t
b_strict
;
vlc_bool_t
b_parse
;
int
i_timeout
;
};
#ifdef HAVE_ZLIB_H
int
do_decompress
(
unsigned
char
*
src
,
unsigned
char
**
_dst
,
int
slen
)
{
int
result
,
dstsize
,
n
;
unsigned
char
*
dst
;
z_stream
d_stream
;
d_stream
.
zalloc
=
(
alloc_func
)
0
;
d_stream
.
zfree
=
(
free_func
)
0
;
d_stream
.
opaque
=
(
voidpf
)
0
;
result
=
inflateInit
(
&
d_stream
);
if
(
result
!=
Z_OK
)
{
printf
(
"inflateInit() failed. Result: %d
\n
"
,
result
);
return
(
-
1
);
}
/*****************************************************************************
* Local prototypes
*****************************************************************************/
d_stream
.
next_in
=
(
Bytef
*
)
src
;
d_stream
.
avail_in
=
slen
;
n
=
0
;
dst
=
NULL
;
do
{
n
++
;
dst
=
(
unsigned
char
*
)
realloc
(
dst
,
n
*
1000
);
d_stream
.
next_out
=
(
Bytef
*
)
&
dst
[(
n
-
1
)
*
1000
];
d_stream
.
avail_out
=
1000
;
result
=
inflate
(
&
d_stream
,
Z_NO_FLUSH
);
if
(
(
result
!=
Z_OK
)
&&
(
result
!=
Z_STREAM_END
)
)
{
printf
(
"Zlib decompression failed. Result: %d
\n
"
,
result
);
return
(
-
1
);
}
}
while
(
(
d_stream
.
avail_out
==
0
)
&&
(
d_stream
.
avail_in
!=
0
)
&&
(
result
!=
Z_STREAM_END
)
);
dstsize
=
d_stream
.
total_out
;
inflateEnd
(
&
d_stream
);
/* Main functions */
static
int
Demux
(
demux_t
*
p_demux
);
static
int
Control
(
demux_t
*
,
int
,
va_list
);
static
void
Run
(
intf_thread_t
*
p_intf
);
*
_dst
=
(
unsigned
char
*
)
realloc
(
dst
,
dstsize
);
/* Main parsing functions */
static
int
ParseConnection
(
vlc_object_t
*
p_obj
,
sdp_t
*
p_sdp
);
static
int
ParseSAP
(
intf_thread_t
*
p_intf
,
uint8_t
*
p_buffer
,
int
i_read
);
static
sdp_t
*
ParseSDP
(
vlc_object_t
*
p_intf
,
char
*
psz_sdp
);
static
sap_announce_t
*
CreateAnnounce
(
intf_thread_t
*
,
uint16_t
,
sdp_t
*
);
return
dstsize
;
}
/* Cache */
static
void
CacheLoad
(
intf_thread_t
*
p_intf
);
static
void
CacheSave
(
intf_thread_t
*
p_intf
);
/* Helper functions */
static
char
*
GetAttribute
(
sdp_t
*
p_sdp
,
const
char
*
psz_search
);
static
int
InitSocket
(
intf_thread_t
*
p_intf
,
char
*
psz_address
,
int
i_port
);
#ifdef HAVE_ZLIB_H
static
int
Decompress
(
unsigned
char
*
psz_src
,
unsigned
char
**
_dst
,
int
i_len
);
#endif
/* Detect multicast addresses */
static
int
ismult
(
char
*
);
/*****************************************************************************
* Open: initialize and create stuff
*****************************************************************************/
...
...
@@ -267,98 +225,87 @@ static int Open( vlc_object_t *p_this )
intf_sys_t
*
p_sys
=
malloc
(
sizeof
(
intf_sys_t
)
);
playlist_t
*
p_playlist
;
playlist_view_t
*
p_view
;
p_sys
->
i_timeout
=
config_GetInt
(
p_intf
,
"sap-timeout"
);
p_sys
->
fd
[
0
]
=
-
1
;
p_sys
->
fd
[
1
]
=
-
1
;
if
(
config_GetInt
(
p_intf
,
"sap-ipv4"
)
)
{
char
*
psz_address
=
config_GetPsz
(
p_intf
,
"sap-addr"
);
network_socket_t
sock
;
module_t
*
p_network
;
if
(
psz_address
==
NULL
||
*
psz_address
==
'\0'
)
{
psz_address
=
strdup
(
HELLO_GROUP
);
}
/* Prepare the network_socket_t structure */
sock
.
i_type
=
NETWORK_UDP
;
sock
.
psz_bind_addr
=
psz_address
;
sock
.
i_bind_port
=
HELLO_PORT
;
sock
.
psz_server_addr
=
""
;
sock
.
i_server_port
=
0
;
sock
.
i_ttl
=
0
;
p_intf
->
p_private
=
(
void
*
)
&
sock
;
p_network
=
module_Need
(
p_intf
,
"network"
,
"ipv4"
,
VLC_TRUE
);
if
(
p_network
)
{
p_sys
->
fd
[
0
]
=
sock
.
i_handle
;
module_Unneed
(
p_intf
,
p_network
);
}
else
{
msg_Warn
(
p_intf
,
"failed to open %s:%d"
,
psz_address
,
HELLO_PORT
);
}
free
(
psz_address
);
p_intf
->
pf_run
=
Run
;
p_intf
->
p_sys
=
p_sys
;
p_sys
->
pi_fd
=
NULL
;
p_sys
->
i_fd
=
0
;
if
(
config_GetInt
(
p_intf
,
"sap-use-cache"
)
)
{
CacheLoad
(
p_intf
);
}
if
(
config_GetInt
(
p_intf
,
"sap-ipv4"
)
)
{
InitSocket
(
p_intf
,
SAP_V4_ADDRESS
,
SAP_PORT
);
}
if
(
config_GetInt
(
p_intf
,
"sap-ipv6"
)
)
{
char
psz_address
[
100
];
char
*
psz_scope
=
config_GetPsz
(
p_intf
,
"sap-ipv6-scope"
);
network_socket_t
sock
;
module_t
*
p_network
;
if
(
psz_scope
==
NULL
||
*
psz_scope
==
'\0'
)
{
psz_scope
=
strdup
(
"8"
);
}
snprintf
(
psz_address
,
100
,
"[%s%c%s]"
,
IPV6_ADDR_1
,
psz_scope
[
0
],
IPV6_ADDR_2
);
free
(
psz_scope
);
sock
.
i_type
=
NETWORK_UDP
;
sock
.
psz_bind_addr
=
psz_address
;
sock
.
i_bind_port
=
HELLO_PORT
;
sock
.
psz_server_addr
=
""
;
sock
.
i_server_port
=
0
;
sock
.
i_ttl
=
0
;
p_intf
->
p_private
=
(
void
*
)
&
sock
;
p_network
=
module_Need
(
p_intf
,
"network"
,
"ipv6"
,
VLC_TRUE
);
if
(
p_network
)
{
p_sys
->
fd
[
1
]
=
sock
.
i_handle
;
module_Unneed
(
p_intf
,
p_network
);
}
else
{
msg_Warn
(
p_intf
,
"failed to open %s:%d"
,
psz_address
,
HELLO_PORT
);
}
/* TODO */
}
if
(
p_sys
->
fd
[
0
]
<=
0
&&
p_sys
->
fd
[
1
]
<=
0
)
/* TODO : Handle additionnal adresses */
if
(
p_sys
->
i_fd
==
0
)
{
msg_Warn
(
p_intf
,
"IPV4 and IPV6 failed"
);
free
(
p_sys
);
msg_Err
(
p_intf
,
"unable to read on any address"
);
return
VLC_EGENERIC
;
}
/* Create our playlist
group
*/
/* Create our playlist
node
*/
p_playlist
=
(
playlist_t
*
)
vlc_object_find
(
p_intf
,
VLC_OBJECT_PLAYLIST
,
FIND_ANYWHERE
);
if
(
p_playlist
)
if
(
!
p_playlist
)
{
playlist_group_t
*
p_group
=
playlist_CreateGroup
(
p_playlist
,
"SAP"
);
p_sys
->
i_group
=
p_group
->
i_id
;
vlc_object_release
(
p_playlist
);
msg_Warn
(
p_intf
,
"unable to find playlist, cancelling SAP listening"
);
return
VLC_EGENERIC
;
}
p_view
=
playlist_ViewFind
(
p_playlist
,
VIEW_CATEGORY
);
p_sys
->
p_node
=
playlist_NodeCreate
(
p_playlist
,
VIEW_CATEGORY
,
_
(
"SAP"
),
p_view
->
p_root
);
vlc_object_release
(
p_playlist
);
p_sys
->
i_announces
=
0
;
p_sys
->
pp_announces
=
NULL
;
p_intf
->
pf_run
=
Run
;
p_intf
->
p_sys
=
p_sys
;
return
VLC_SUCCESS
;
}
/*****************************************************************************
* OpenDemux: initialize and create stuff
*****************************************************************************/
static
int
OpenDemux
(
vlc_object_t
*
p_this
)
{
demux_t
*
p_demux
=
(
demux_t
*
)
p_this
;
uint8_t
*
p_peek
;
/* Probe for SDP */
if
(
p_demux
->
s
)
{
if
(
stream_Peek
(
p_demux
->
s
,
&
p_peek
,
7
)
<
7
)
{
msg_Err
(
p_demux
,
"cannot peek"
);
return
VLC_EGENERIC
;
}
if
(
strncmp
(
(
char
*
)
p_peek
,
"v=0
\r\n
"
,
5
)
&&
strncmp
(
(
char
*
)
p_peek
,
"v=0
\n
"
,
4
)
&&
(
p_peek
[
0
]
<
'a'
||
p_peek
[
0
]
>
'z'
||
p_peek
[
1
]
!=
'='
)
)
{
msg_Warn
(
p_demux
,
"SDP (UDP) module discarded"
);
return
VLC_EGENERIC
;
}
}
p_demux
->
pf_control
=
Control
;
p_demux
->
pf_demux
=
Demux
;
return
VLC_SUCCESS
;
}
...
...
@@ -372,30 +319,34 @@ static void Close( vlc_object_t *p_this )
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
int
i
;
if
(
p_sys
->
fd
[
0
]
>
0
)
for
(
i
=
p_sys
->
i_fd
-
1
;
i
>=
0
;
i
--
)
{
close
(
p_sys
->
fd
[
0
]
);
net_Close
(
p_sys
->
pi_fd
[
i
]
);
}
if
(
p_sys
->
fd
[
1
]
>
0
)
if
(
config_GetInt
(
p_intf
,
"sap-use-cache"
)
)
{
close
(
p_sys
->
fd
[
1
]
);
CacheSave
(
p_intf
);
}
for
(
i
=
0
;
i
<
p_sys
->
i_announces
;
i
++
)
for
(
i
=
p_sys
->
i_announces
-
1
;
i
>=
0
;
i
--
)
{
if
(
p_sys
->
pp_announces
[
i
]
->
psz_name
)
free
(
p_sys
->
pp_announces
[
i
]
->
psz_name
);
if
(
p_sys
->
pp_announces
[
i
]
->
psz_uri
)
free
(
p_sys
->
pp_announces
[
i
]
->
psz_uri
);
free
(
p_sys
->
pp_announces
[
i
]
);
RemoveAnnounce
(
p_intf
,
p_sys
->
pp_announces
[
i
]
);
}
free
(
p_sys
->
pp_announces
);
free
(
p_sys
);
}
/*****************************************************************************
* Run: sap thread
* CloseDemux: Close the demuxer
*****************************************************************************/
static
void
CloseDemux
(
vlc_object_t
*
p_this
)
{
}
/*****************************************************************************
* Run: main SAP thread
*****************************************************************************
* Listens to SAP packets, and sends them to packet_handle
*****************************************************************************/
...
...
@@ -403,29 +354,27 @@ static void Close( vlc_object_t *p_this )
static
void
Run
(
intf_thread_t
*
p_intf
)
{
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
uint8_t
buffer
[
MAX_SAP_BUFFER
+
1
];
uint8_t
*
p_end
;
/* Dirty hack to slow down the startup of the sap interface */
msleep
(
500000
);
uint8_t
*
p_buffer
;
/* Dirty hack to slow down the startup of the sap interface */
/* Unneeded now : our node is in no_select mode */
// msleep( 500000 );
/* read SAP packets */
while
(
!
p_intf
->
b_die
)
{
playlist_t
*
p_playlist
=
NULL
;
int
i
;
int
i_read
=
NetRead
(
p_intf
,
p_sys
->
fd
,
buffer
,
MAX_SAP_BUFFER
);
uint8_t
*
p_sdp
;
int
i_version
;
int
i_address_type
;
int
b_reserved
;
int
b_message_type
;
int
b_encrypted
;
int
b_compressed
;
unsigned
char
*
p_decompressed_buffer
;
int
i_decompressed_size
;
p_buffer
=
(
uint8_t
*
)
malloc
(
MAX_SAP_BUFFER
);
if
(
!
p_buffer
)
{
msg_Err
(
p_intf
,
"out of memory"
);
p_intf
->
b_die
=
VLC_TRUE
;
continue
;
}
int
i_read
=
net_Select
(
p_intf
,
p_intf
->
p_sys
->
pi_fd
,
p_intf
->
p_sys
->
i_fd
,
p_buffer
,
MAX_SAP_BUFFER
,
500000
);
#if 0
/* Check for items that need deletion */
for( i = 0 ; i< p_intf->p_sys->i_announces ; i++ )
{
...
...
@@ -437,7 +386,7 @@ static void Run( intf_thread_t *p_intf )
p_intf->p_sys->pp_announces[i]->psz_name,
i , p_intf->p_sys->i_announces );
/* Remove the playlist item */
/* Remove the playlist item */
p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist )
...
...
@@ -464,562 +413,556 @@ static void Run( intf_thread_t *p_intf )
}
}
#endif
/* Minimum length is > 6 */
if
(
i_read
<=
6
)
{
if
(
i_read
<
0
)
{
msg_Warn
(
p_intf
,
"
Cannot read in the socket
"
);
msg_Warn
(
p_intf
,
"
socket read error
"
);
}
continue
;
}
buffer
[
i_read
]
=
'\0'
;
p_end
=
&
buffer
[
i_read
];
p_buffer
[
i_read
]
=
'\0'
;
/* Parse the packet */
ParseSAP
(
p_intf
,
p_buffer
,
i_read
);
}
}
/**********************************************************************
* Demux: reads and demuxes data packets
* Return -1 if error, 0 if EOF, 1 else
**********************************************************************/
static
int
Demux
(
demux_t
*
p_demux
)
{
int
i_max_sdp
=
1024
;
int
i_sdp
=
0
;
char
*
psz_sdp
=
(
char
*
)
malloc
(
i_max_sdp
);
sdp_t
*
p_sdp
;
playlist_t
*
p_playlist
;
/* Gather the complete sdp file */
for
(
;;
)
{
int
i_read
=
stream_Read
(
p_demux
->
s
,
&
psz_sdp
[
i_sdp
],
i_max_sdp
-
i_sdp
-
1
);
/* Parse the SAP header */
i_version
=
buffer
[
0
]
>>
5
;
if
(
i_version
!=
1
)
{
msg_Dbg
(
p_intf
,
"strange sap version %d found"
,
i_version
);
}
i_address_type
=
buffer
[
0
]
&
0x10
;
b_reserved
=
buffer
[
0
]
&
0x08
;
if
(
b_reserved
!=
0
)
{
msg_Dbg
(
p_intf
,
"reserved bit incorrectly set"
);
}
b_message_type
=
buffer
[
0
]
&
0x04
;
if
(
b_message_type
!=
0
)
{
msg_Dbg
(
p_intf
,
"got session deletion packet"
);
}
b_encrypted
=
buffer
[
0
]
&
0x02
;
if
(
b_encrypted
)
{
msg_Dbg
(
p_intf
,
"encrypted packet"
);
}
b_compressed
=
buffer
[
0
]
&
0x01
;
p_sdp
=
&
buffer
[
4
];
if
(
i_address_type
==
0
)
/* ipv4 source address */
{
p_sdp
+=
4
;
}
else
/* ipv6 source address */
{
p_sdp
+=
16
;
}
if
(
b_compressed
)
{
#ifdef HAVE_ZLIB_H
i_decompressed_size
=
do_decompress
(
p_sdp
,
&
p_decompressed_buffer
,
i_read
-
(
p_sdp
-
buffer
)
);
if
(
i_decompressed_size
>
0
&&
i_decompressed_size
<
MAX_SAP_BUFFER
)
{
memcpy
(
p_sdp
,
p_decompressed_buffer
,
i_decompressed_size
);
p_sdp
[
i_decompressed_size
]
=
'\0'
;
p_end
=
&
p_sdp
[
i_decompressed_size
];
free
(
p_decompressed_buffer
);
}
#else
msg_Warn
(
p_intf
,
"Ignoring compressed sap packet"
);
#endif
}
p_sdp
+=
buffer
[
1
];
/* size of signature */
while
(
p_sdp
<
p_end
-
1
&&
*
p_sdp
!=
'\0'
&&
p_sdp
[
0
]
!=
'v'
&&
p_sdp
[
1
]
!=
'='
)
{
p_sdp
++
;
}
if
(
*
p_sdp
==
'\0'
)
{
p_sdp
++
;
}
if
(
p_sdp
<
p_end
)
if
(
i_read
<
0
)
{
sess_descr_t
*
p_sd
=
parse_sdp
(
(
vlc_object_t
*
)
p_intf
,
p_sdp
);
if
(
p_sd
)
{
sess_toitem
(
p_intf
,
p_sd
);
free_sd
(
p_sd
);
}
msg_Err
(
p_demux
,
"failed to read SDP"
);
return
VLC_EGENERIC
;
}
else
i_sdp
+=
i_read
;
if
(
i_read
<
i_max_sdp
-
i_sdp
-
1
)
{
msg_Warn
(
p_intf
,
"ditching sap packet"
);
psz_sdp
[
i_sdp
]
=
'\0'
;
break
;
}
memset
(
buffer
,
0
,
MAX_SAP_BUFFER
);
}
i_max_sdp
+=
1000
;
psz_sdp
=
(
uint8_t
*
)
realloc
(
psz_sdp
,
i_max_sdp
);
}
p_sdp
=
ParseSDP
(
VLC_OBJECT
(
p_demux
),
psz_sdp
);
if
(
!
p_sdp
)
return
-
1
;
if
(
p_sdp
->
i_media
>
1
)
{
return
-
1
;
}
if
(
ParseConnection
(
VLC_OBJECT
(
p_demux
),
p_sdp
)
)
{
p_sdp
->
psz_uri
=
NULL
;
}
if
(
p_sdp
->
psz_uri
==
NULL
)
return
VLC_EGENERIC
;
p_playlist
=
(
playlist_t
*
)
vlc_object_find
(
p_demux
,
VLC_OBJECT_PLAYLIST
,
FIND_ANYWHERE
);
playlist_Add
(
p_playlist
,
p_sdp
->
psz_uri
,
p_sdp
->
psz_sessionname
,
PLAYLIST_APPEND
,
PLAYLIST_END
);
vlc_object_release
(
p_playlist
);
return
VLC_SUCCESS
;
}
/**********************************************************************
* cfield_parse
*********************************************************************
* put into *ppsz_uri, the the uri in the cfield, psz_cfield.
*********************************************************************/
static
int
Control
(
demux_t
*
p_demux
,
int
i_query
,
va_list
args
)
{
return
VLC_EGENERIC
;
}
/**************************************************************
* Local functions
**************************************************************/
static
void
cfield_parse
(
char
*
psz_cfield
,
char
**
ppsz_uri
)
static
int
ParseSAP
(
intf_thread_t
*
p_intf
,
uint8_t
*
p_buffer
,
int
i_read
)
{
char
*
psz_pos
;
if
(
psz_cfield
)
int
i_version
,
i_address_type
,
i_hash
,
i
;
uint8_t
*
psz_sdp
;
sdp_t
*
p_sdp
;
vlc_bool_t
b_compressed
;
vlc_bool_t
b_need_delete
=
VLC_FALSE
;
#ifdef HAVE_ZLIB_H
int
i_decompressed_size
;
uint8_t
*
p_decompressed_buffer
;
#endif
/* First, check the sap announce is correct */
i_version
=
p_buffer
[
0
]
>>
5
;
if
(
i_version
!=
1
)
{
psz_pos
=
psz_cfield
;
msg_Dbg
(
p_intf
,
"strange sap version %d found"
,
i_version
);
}
while
(
*
psz_pos
!=
' '
&&
*
psz_pos
!=
'\0'
)
{
psz_pos
++
;
}
psz_pos
++
;
while
(
*
psz_pos
!=
' '
&&
*
psz_pos
!=
'\0'
)
{
psz_pos
++
;
}
psz_pos
++
;
*
ppsz_uri
=
psz_pos
;
while
(
*
psz_pos
!=
' '
&&
*
psz_pos
!=
'/'
&&
*
psz_pos
!=
'\0'
)
{
psz_pos
++
;
}
*
psz_pos
=
'\0'
;
i_address_type
=
p_buffer
[
0
]
&
0x10
;
if
(
(
p_buffer
[
0
]
&
0x08
)
!=
0
)
{
msg_Dbg
(
p_intf
,
"reserved bit incorrectly set"
);
return
VLC_EGENERIC
;
}
else
if
(
(
p_buffer
[
0
]
&
0x04
)
!=
0
)
{
ppsz_uri
=
NULL
;
msg_Dbg
(
p_intf
,
"session deletion packet"
);
b_need_delete
=
VLC_TRUE
;
}
return
;
}
if
(
p_buffer
[
0
]
&
0x02
)
{
msg_Dbg
(
p_intf
,
"encrypted packet, unsupported"
);
return
VLC_EGENERIC
;
}
/**********************************************************************
* mfield_parse
*********************************************************************
* put into *ppsz_proto, and *ppsz_port, the protocol and the port.
*********************************************************************/
b_compressed
=
p_buffer
[
0
]
&
0x01
;
i_hash
=
(
p_buffer
[
2
]
<<
8
)
+
p_buffer
[
3
];
static
void
mfield_parse
(
char
*
psz_mfield
,
char
**
ppsz_proto
,
char
**
ppsz_port
)
{
char
*
psz_pos
;
char
*
psz_media
;
if
(
psz_mfield
)
if
(
p_intf
->
p_sys
->
b_strict
&&
i_hash
==
0
)
{
psz_pos
=
psz_mfield
;
psz_media
=
psz_mfield
;
while
(
*
psz_pos
!=
'\0'
&&
*
psz_pos
!=
' '
)
{
psz_pos
++
;
}
if
(
*
psz_pos
!=
'\0'
)
{
*
psz_pos
=
'\0'
;
if
(
strcmp
(
psz_media
,
"video"
)
&&
strcmp
(
psz_media
,
"audio"
)
)
{
*
ppsz_proto
=
NULL
;
*
ppsz_port
=
NULL
;
return
;
}
}
psz_pos
++
;
*
ppsz_port
=
psz_pos
;
while
(
*
psz_pos
!=
'\0'
&&
*
psz_pos
!=
' '
&&
*
psz_pos
!=
'/'
)
{
psz_pos
++
;
}
if
(
*
psz_pos
==
'/'
)
// FIXME does not support multi-port
{
*
psz_pos
=
'\0'
;
psz_pos
++
;
while
(
*
psz_pos
!=
'\0'
&&
*
psz_pos
!=
' '
)
{
psz_pos
++
;
}
}
*
psz_pos
=
'\0'
;
psz_pos
++
;
*
ppsz_proto
=
psz_pos
;
while
(
*
psz_pos
!=
'\0'
&&
*
psz_pos
!=
' '
&&
*
psz_pos
!=
'/'
)
msg_Dbg
(
p_intf
,
"strict mode, discarding announce with null id hash"
);
return
VLC_EGENERIC
;
}
psz_sdp
=
&
p_buffer
[
4
];
if
(
i_address_type
==
0
)
/* ipv4 source address */
{
psz_sdp
+=
4
;
}
else
/* ipv6 source address */
{
psz_sdp
+=
16
;
}
if
(
b_compressed
)
{
#ifdef HAVE_ZLIB_H
i_decompressed_size
=
Decompress
(
psz_sdp
,
&
p_decompressed_buffer
,
i_read
-
(
psz_sdp
-
p_buffer
)
);
if
(
i_decompressed_size
>
0
&&
i_decompressed_size
<
MAX_SAP_BUFFER
)
{
*
psz_pos
=
tolower
(
*
psz_pos
);
psz_pos
++
;
memcpy
(
psz_sdp
,
p_decompressed_buffer
,
i_decompressed_size
);
psz_sdp
[
i_decompressed_size
]
=
'\0'
;
free
(
p_decompressed_buffer
);
}
*
psz_pos
=
'\0'
;
#else
msg_Warn
(
p_intf
,
"Ignoring compressed sap packet"
);
return
VLC_EGENERIC
;
#endif
}
else
/* Add the size of authentification info */
psz_sdp
+=
p_buffer
[
1
];
/* Skip payload type */
/* Handle announces without \0 between SAP and SDP */
while
(
*
psz_sdp
!=
'\0'
&&
(
psz_sdp
[
0
]
!=
'v'
&&
psz_sdp
[
1
]
!=
'='
)
)
{
*
ppsz_proto
=
NULL
;
*
ppsz_port
=
NULL
;
psz_sdp
++
;
}
return
;
}
if
(
*
psz_sdp
==
'\0'
)
{
psz_sdp
++
;
}
/*******************************************************************
* sess_toitem : changes a sess_descr_t into a hurd of
* playlist_item_t, which are enqueued.
*******************************************************************
* Note : does not support sessions that take place on consecutive
* port or adresses yet.
*******************************************************************/
fprintf
(
stderr
,
"
\n\n
%s
\n\n
"
,
psz_sdp
);
static
void
sess_toitem
(
intf_thread_t
*
p_intf
,
sess_descr_t
*
p_sd
)
{
struct
sap_announce_t
*
p_announce
;
char
*
psz_uri
,
*
psz_proto
,
*
psz_item_uri
;
char
*
psz_port
;
char
*
psz_uri_default
;
int
i_count
,
i
,
i_id
=
0
;
vlc_bool_t
b_http
=
VLC_FALSE
;
char
*
psz_http_path
=
NULL
;
playlist_t
*
p_playlist
=
NULL
;
playlist_item_t
*
p_item
;
/* Parse SDP info */
p_sdp
=
ParseSDP
(
VLC_OBJECT
(
p_intf
),
psz_sdp
);
psz_uri_default
=
NULL
;
if
(
p_sd
->
i_media
>
1
||
!
config_GetInt
(
p_intf
,
"sap-parse"
)
)
if
(
p_sdp
==
NULL
)
{
asprintf
(
&
psz_uri
,
"sdp://%s"
,
p_sd
->
psz_sdp
);
/* Check if we have already added the item */
for
(
i
=
0
;
i
<
p_intf
->
p_sys
->
i_announces
;
i
++
)
return
VLC_EGENERIC
;
}
/* Decide whether we should add a playlist item for this SDP */
/* Multi-media or no-parse -> pass to LIVE.COM */
if
(
p_sdp
->
i_media
>
1
||
p_intf
->
p_sys
->
b_parse
==
VLC_FALSE
)
{
asprintf
(
&
p_sdp
->
psz_uri
,
"sdp://%s"
,
p_sdp
->
psz_sdp
);
}
else
{
/* Parse connection information (c= & m= ) */
if
(
ParseConnection
(
VLC_OBJECT
(
p_intf
),
p_sdp
)
)
{
p_sdp
->
psz_uri
=
NULL
;
}
}
if
(
p_sdp
->
psz_uri
==
NULL
)
return
VLC_EGENERIC
;
for
(
i
=
0
;
i
<
p_intf
->
p_sys
->
i_announces
;
i
++
)
{
/* FIXME: slow */
/* FIXME: we create a new announce each time the sdp changes */
if
(
!
strcmp
(
p_intf
->
p_sys
->
pp_announces
[
i
]
->
p_sdp
->
psz_sdp
,
p_sdp
->
psz_sdp
)
)
{
if
(
!
strcmp
(
p_intf
->
p_sys
->
pp_announces
[
i
]
->
psz_uri
,
psz_uri
)
)
if
(
b_need_delete
)
{
RemoveAnnounce
(
p_intf
,
p_intf
->
p_sys
->
pp_announces
[
i
]);
return
VLC_SUCCESS
;
}
else
{
p_intf
->
p_sys
->
pp_announces
[
i
]
->
i_last
=
mdate
();
free
(
psz_uri
);
return
;
}
return
VLC_SUCCESS
;
}
/* Add it to the playlist */
p_playlist
=
vlc_object_find
(
p_intf
,
VLC_OBJECT_PLAYLIST
,
FIND_ANYWHERE
);
i_id
=
playlist_Add
(
p_playlist
,
psz_uri
,
p_sd
->
psz_sessionname
,
PLAYLIST_CHECK_INSERT
,
PLAYLIST_END
);
if
(
i_id
!=
-
1
)
{
playlist_item_t
*
p_item
=
playlist_ItemGetById
(
p_playlist
,
i_id
);
playlist_ItemSetGroup
(
p_item
,
p_intf
->
p_sys
->
i_group
);
}
}
/* Add item */
if
(
p_sdp
->
i_media
>
1
)
{
msg_Dbg
(
p_intf
,
"passing to LIVE.COM"
);
}
/* Remember it */
p_announce
=
(
struct
sap_announce_t
*
)
malloc
(
sizeof
(
struct
sap_announce_t
)
);
if
(
p_sd
->
psz_sessionname
)
{
p_announce
->
psz_name
=
strdup
(
p_sd
->
psz_sessionname
);
}
else
{
p_announce
->
psz_name
=
strdup
(
""
);
}
if
(
psz_uri
)
{
p_announce
->
psz_uri
=
strdup
(
psz_uri
);
}
else
{
p_announce
->
psz_uri
=
strdup
(
""
);
}
p_announce
->
i_id
=
i_id
;
p_announce
->
i_last
=
mdate
();
CreateAnnounce
(
p_intf
,
i_hash
,
p_sdp
);
return
VLC_SUCCESS
;
}
sap_announce_t
*
CreateAnnounce
(
intf_thread_t
*
p_intf
,
uint16_t
i_hash
,
sdp_t
*
p_sdp
)
{
playlist_t
*
p_playlist
;
playlist_item_t
*
p_item
,
*
p_child
;
char
*
psz_value
;
sap_announce_t
*
p_sap
=
(
sap_announce_t
*
)
malloc
(
sizeof
(
sap_announce_t
)
);
if
(
!
p_sap
)
{
msg_Err
(
p_intf
,
"out of memory"
);
p_intf
->
b_die
=
VLC_TRUE
;
return
NULL
;
}
p_sap
->
i_last
=
mdate
();
p_sap
->
i_hash
=
i_hash
;
p_sap
->
p_sdp
=
p_sdp
;
p_sap
->
p_item
=
NULL
;
INSERT_ELEM
(
p_intf
->
p_sys
->
pp_announces
,
p_intf
->
p_sys
->
i_announces
,
p_intf
->
p_sys
->
i_announces
,
p_announce
);
/* Create the playlist item here */
p_item
=
playlist_ItemNew
(
p_intf
,
p_sap
->
p_sdp
->
psz_uri
,
p_sap
->
p_sdp
->
psz_sessionname
);
vlc_object_release
(
p_playlist
);
free
(
psz_uri
);
return
;
if
(
!
p_item
)
{
return
NULL
;
}
cfield_parse
(
p_sd
->
psz_connection
,
&
psz_uri_default
);
psz_value
=
GetAttribute
(
p_sap
->
p_sdp
,
"x-plgroup"
);
if
(
psz_value
==
NULL
)
{
psz_value
=
GetAttribute
(
p_sap
->
p_sdp
,
"plgroup"
);
}
for
(
i_count
=
0
;
i_count
<
p_sd
->
i_media
;
i_count
++
)
p_playlist
=
(
playlist_t
*
)
vlc_object_find
(
p_intf
,
VLC_OBJECT_PLAYLIST
,
FIND_ANYWHERE
);
if
(
!
p_playlist
)
{
int
i_group
=
p_intf
->
p_sys
->
i_group
;
int
i_packetsize
=
config_GetInt
(
p_intf
,
"mtu"
);
msg_Err
(
p_intf
,
"playlist not found"
);
/* FIXME : Free */
return
NULL
;
}
/* Build what we have to put in psz_item_uri, with the m and
* c fields */
if
(
psz_value
!=
NULL
)
{
p_child
=
playlist_ChildSearchName
(
p_intf
->
p_sys
->
p_node
,
psz_value
);
if
(
!
p_sd
->
pp_media
[
i_count
]
)
if
(
p_child
==
NULL
)
{
return
;
p_child
=
playlist_NodeCreate
(
p_playlist
,
VIEW_CATEGORY
,
psz_value
,
p_intf
->
p_sys
->
p_node
);
}
}
else
{
p_child
=
p_intf
->
p_sys
->
p_node
;
}
p_item
->
i_flags
&=
~
PLAYLIST_SKIP_FLAG
;
playlist_NodeAddItem
(
p_playlist
,
p_item
,
VIEW_CATEGORY
,
p_child
,
PLAYLIST_APPEND
,
PLAYLIST_END
);
vlc_object_release
(
p_playlist
);
p_sap
->
p_item
=
p_item
;
TAB_APPEND
(
p_intf
->
p_sys
->
i_announces
,
p_intf
->
p_sys
->
pp_announces
,
p_sap
);
return
p_sap
;
}
mfield_parse
(
p_sd
->
pp_media
[
i_count
]
->
psz_medianame
,
&
psz_proto
,
&
psz_port
);
static
char
*
GetAttribute
(
sdp_t
*
p_sdp
,
const
char
*
psz_search
)
{
int
i
;
if
(
!
psz_proto
||
!
psz_port
)
for
(
i
=
0
;
i
<
p_sdp
->
i_attributes
;
i
++
)
{
if
(
!
strncmp
(
p_sdp
->
pp_attributes
[
i
]
->
psz_field
,
psz_search
,
strlen
(
p_sdp
->
pp_attributes
[
i
]
->
psz_field
)
)
)
{
return
;
return
p_sdp
->
pp_attributes
[
i
]
->
psz_value
;
}
}
return
NULL
;
}
if
(
p_sd
->
pp_media
[
i_count
]
->
psz_mediaconnection
)
/* Fill p_sdp->psz_uri */
static
int
ParseConnection
(
vlc_object_t
*
p_obj
,
sdp_t
*
p_sdp
)
{
char
*
psz_eof
;
char
*
psz_parse
;
char
*
psz_uri
=
NULL
;
char
*
psz_proto
=
NULL
;
int
i_port
=
0
;
/* Parse c= field */
if
(
p_sdp
->
psz_connection
)
{
psz_parse
=
p_sdp
->
psz_connection
;
psz_eof
=
strchr
(
psz_parse
,
' '
);
if
(
psz_eof
)
{
cfield_parse
(
p_sd
->
pp_media
[
i_count
]
->
psz_mediaconnection
,
&
psz_uri
)
;
*
psz_eof
=
'\0'
;
psz_parse
=
psz_eof
+
1
;
}
else
{
psz_uri
=
psz_uri_default
;
msg_Warn
(
p_obj
,
"unable to parse c field (1)"
);
return
VLC_EGENERIC
;
}
if
(
psz_uri
==
NULL
)
{
return
;
}
psz_eof
=
strchr
(
psz_parse
,
' '
);
for
(
i
=
0
;
i
<
p_sd
->
i_attributes
;
i
++
)
if
(
psz_eof
)
{
if
(
!
strcasecmp
(
p_sd
->
pp_attributes
[
i
]
->
psz_field
,
"type"
)
&&
strstr
(
p_sd
->
pp_attributes
[
i
]
->
psz_value
,
"http"
)
)
*
psz_eof
=
'\0'
;
if
(
!
strncmp
(
psz_parse
,
"IP4"
,
3
)
)
{
b_http
=
VLC_TRUE
;
p_sdp
->
i_in
=
4
;
}
if
(
!
strcasecmp
(
p_sd
->
pp_attributes
[
i
]
->
psz_field
,
"http-path"
)
)
else
if
(
!
strncmp
(
psz_parse
,
"IP6"
,
3
)
)
{
psz_http_path
=
strdup
(
p_sd
->
pp_attributes
[
i
]
->
psz_value
);
}
if
(
(
!
strcasecmp
(
p_sd
->
pp_attributes
[
i
]
->
psz_field
,
"plgroup"
)
)
||
(
!
strcasecmp
(
p_sd
->
pp_attributes
[
i
]
->
psz_field
,
"x-plgroup"
)
)
)
{
int
i_group_id
;
p_playlist
=
(
playlist_t
*
)
vlc_object_find
(
p_intf
,
VLC_OBJECT_PLAYLIST
,
FIND_ANYWHERE
);
if
(
p_playlist
==
NULL
)
{
return
;
}
i_group_id
=
playlist_GroupToId
(
p_playlist
,
p_sd
->
pp_attributes
[
i
]
->
psz_value
);
if
(
i_group_id
!=
0
)
{
i_group
=
i_group_id
;
}
else
{
playlist_group_t
*
p_group
=
playlist_CreateGroup
(
p_playlist
,
p_sd
->
pp_attributes
[
i
]
->
psz_value
);
i_group
=
p_group
->
i_id
;
}
vlc_object_release
(
p_playlist
);
}
if
(
!
strcasecmp
(
p_sd
->
pp_attributes
[
i
]
->
psz_field
,
"packetsize"
)
)
{
i_packetsize
=
strtol
(
p_sd
->
pp_attributes
[
i
]
->
psz_value
,
NULL
,
10
);
}
}
/* Filling psz_uri */
if
(
b_http
==
VLC_FALSE
)
{
if
(
ismult
(
psz_uri
)
)
{
asprintf
(
&
psz_item_uri
,
"%s://@%s:%s"
,
psz_proto
,
psz_uri
,
psz_port
);
p_sdp
->
i_in
=
6
;
}
else
{
asprintf
(
&
psz_item_uri
,
"%s://%s:%s"
,
psz_proto
,
psz_uri
,
psz_port
);
p_sdp
->
i_in
=
0
;
}
psz_parse
=
psz_eof
+
1
;
}
else
{
if
(
psz_http_path
==
NULL
)
{
psz_http_path
=
strdup
(
"/"
);
}
if
(
*
psz_http_path
==
'/'
)
{
asprintf
(
&
psz_item_uri
,
"%s://%s:%s%s"
,
psz_proto
,
psz_uri
,
psz_port
,
psz_http_path
);
}
else
{
asprintf
(
&
psz_item_uri
,
"%s://%s:%s/%s"
,
psz_proto
,
psz_uri
,
psz_port
,
psz_http_path
);
}
if
(
psz_http_path
)
{
free
(
psz_http_path
);
}
msg_Warn
(
p_obj
,
"unable to parse c field (2)"
);
return
VLC_EGENERIC
;
}
/* Check if we already know this item */
for
(
i
=
0
;
i
<
p_intf
->
p_sys
->
i_announces
;
i
++
)
{
if
(
!
strcmp
(
p_intf
->
p_sys
->
pp_announces
[
i
]
->
psz_uri
,
psz_item_uri
)
)
{
p_intf
->
p_sys
->
pp_announces
[
i
]
->
i_last
=
mdate
();
psz_eof
=
strchr
(
psz_parse
,
'/'
);
/* Check if the name changed */
if
(
strcmp
(
p_intf
->
p_sys
->
pp_announces
[
i
]
->
psz_name
,
p_sd
->
psz_sessionname
)
)
{
playlist_item_t
*
p_item
;
p_playlist
=
vlc_object_find
(
p_intf
,
VLC_OBJECT_PLAYLIST
,
FIND_ANYWHERE
);
msg_Dbg
(
p_intf
,
"Name changed (%s -> %s) for %s"
,
p_intf
->
p_sys
->
pp_announces
[
i
]
->
psz_name
,
p_sd
->
psz_sessionname
,
psz_item_uri
);
p_item
=
playlist_ItemGetById
(
p_playlist
,
p_intf
->
p_sys
->
pp_announces
[
i
]
->
i_id
);
/* Change the name in the item */
if
(
p_item
)
{
vlc_mutex_lock
(
&
p_item
->
input
.
lock
);
if
(
p_item
->
input
.
psz_name
)
free
(
p_item
->
input
.
psz_name
);
p_item
->
input
.
psz_name
=
strdup
(
p_sd
->
psz_sessionname
);
vlc_mutex_unlock
(
&
p_item
->
input
.
lock
);
}
/* Update the stored name */
if
(
p_intf
->
p_sys
->
pp_announces
[
i
]
->
psz_name
)
free
(
p_intf
->
p_sys
->
pp_announces
[
i
]
->
psz_name
);
p_intf
->
p_sys
->
pp_announces
[
i
]
->
psz_name
=
strdup
(
p_sd
->
psz_sessionname
);
vlc_object_release
(
p_playlist
);
}
free
(
psz_item_uri
);
return
;
}
if
(
psz_eof
)
{
*
psz_eof
=
0
;
psz_uri
=
strdup
(
psz_parse
);
}
else
{
msg_Warn
(
p_obj
,
"unable to parse c field (3)"
);
return
VLC_EGENERIC
;
}
/* Add the item in the playlist */
p_playlist
=
vlc_object_find
(
p_intf
,
VLC_OBJECT_PLAYLIST
,
FIND_ANYWHERE
);
}
p_item
=
playlist_ItemNew
(
p_intf
,
psz_item_uri
,
p_sd
->
psz_sessionname
);
/* Parse m= field */
if
(
p_sdp
->
psz_media
)
{
psz_parse
=
p_sdp
->
psz_media
;
if
(
p_item
)
psz_eof
=
strchr
(
psz_parse
,
' '
);
if
(
psz_eof
)
{
playlist_ItemSetGroup
(
p_item
,
i_group
);
if
(
i_packetsize
>
config_GetInt
(
p_intf
,
"mtu"
)
)
*
psz_eof
=
'\0'
;
if
(
strncmp
(
psz_parse
,
"audio"
,
5
)
&&
strncmp
(
psz_parse
,
"video"
,
5
)
)
{
char
*
psz_packetsize_option
;
asprintf
(
&
psz_packetsize_option
,
"mtu=%i"
,
i_packetsize
);
playlist_ItemAddOption
(
p_item
,
psz_packetsize_option
);
free
(
psz_packetsize_option
);
msg_Warn
(
p_obj
,
"unhandled media type -%s-"
,
psz_parse
);
return
VLC_EGENERIC
;
}
playlist_AddItem
(
p_playlist
,
p_item
,
PLAYLIST_CHECK_INSERT
,
PLAYLIST_END
);
psz_parse
=
psz_eof
+
1
;
}
else
{
msg_Warn
(
p_obj
,
"unable to parse m field (1)"
);
return
VLC_EGENERIC
;
}
/* Then remember it */
p_announce
=
(
struct
sap_announce_t
*
)
malloc
(
sizeof
(
struct
sap_announce_t
)
);
if
(
p_sd
->
psz_sessionname
)
psz_eof
=
strchr
(
psz_parse
,
' '
);
if
(
psz_eof
)
{
p_announce
->
psz_name
=
strdup
(
p_sd
->
psz_sessionname
);
*
psz_eof
=
'\0'
;
/* FIXME : multiple port ! */
i_port
=
atoi
(
psz_parse
);
if
(
i_port
<=
0
||
i_port
>=
65536
)
{
msg_Warn
(
p_obj
,
"invalid transport port %i"
,
i_port
);
}
psz_parse
=
psz_eof
+
1
;
}
else
{
p_announce
->
psz_name
=
strdup
(
""
);
msg_Warn
(
p_obj
,
"unable to parse m field (2)"
);
return
VLC_EGENERIC
;
}
if
(
psz_item_uri
)
psz_eof
=
strchr
(
psz_parse
,
' '
);
if
(
psz_eof
)
{
p_announce
->
psz_uri
=
strdup
(
psz_item_uri
);
*
psz_eof
=
'\0'
;
psz_proto
=
strdup
(
psz_parse
);
}
else
{
p_announce
->
psz_uri
=
strdup
(
""
);
msg_Warn
(
p_obj
,
"unable to parse m field (3)"
);
return
VLC_EGENERIC
;
}
p_announce
->
i_id
=
i_id
;
}
p_announce
->
i_last
=
mdate
();
/* FIXME: HTTP support */
vlc_object_release
(
p_playlist
);
if
(
i_port
==
0
)
{
i_port
=
1234
;
}
INSERT_ELEM
(
p_intf
->
p_sys
->
pp_announces
,
p_intf
->
p_sys
->
i_announces
,
p_intf
->
p_sys
->
i_announces
,
p_announce
);
free
(
psz_item_uri
);
if
(
ismult
(
psz_uri
)
)
{
asprintf
(
&
p_sdp
->
psz_uri
,
"%s://@%s:%i"
,
psz_proto
,
psz_uri
,
i_port
);
}
else
{
asprintf
(
&
p_sdp
->
psz_uri
,
"%s://%s:%i"
,
psz_proto
,
psz_uri
,
i_port
);
}
return
VLC_SUCCESS
;
}
/***********************************************************************
*
parse_sdp
: SDP parsing
*
ParseSDP
: SDP parsing
* *********************************************************************
*
Make a sess_descr_t with a psz
*
Validate SDP and parse all fields
***********************************************************************/
static
sess_descr_t
*
parse_sdp
(
vlc_object_t
*
p_parent
,
char
*
p_packet
)
static
sdp_t
*
ParseSDP
(
vlc_object_t
*
p_obj
,
char
*
psz_sdp
)
{
s
ess_descr_t
*
sd
;
s
dp_t
*
p_sdp
;
if
(
p
_packet
[
0
]
!=
'v'
||
p_packet
[
1
]
!=
'='
)
if
(
p
sz_sdp
[
0
]
!=
'v'
||
psz_sdp
[
1
]
!=
'='
)
{
msg_Warn
(
p_
parent
,
"bad SDP packet"
);
msg_Warn
(
p_
obj
,
"bad SDP packet"
);
return
NULL
;
}
sd
=
malloc
(
sizeof
(
sess_descr_t
)
);
sd
->
psz_sessionname
=
NULL
;
sd
->
psz_connection
=
NULL
;
sd
->
psz_sdp
=
strdup
(
p_packet
);
p_sdp
=
(
sdp_t
*
)
malloc
(
sizeof
(
sdp_t
)
);
sd
->
i_media
=
0
;
sd
->
pp_media
=
NULL
;
sd
->
i_attributes
=
0
;
sd
->
pp_attributes
=
NULL
;
p_sdp
->
psz_sdp
=
strdup
(
psz_sdp
);
while
(
*
p_packet
!=
'\0'
)
{
char
*
psz_end
;
p_sdp
->
psz_sessionname
=
NULL
;
p_sdp
->
psz_media
=
NULL
;
p_sdp
->
psz_connection
=
NULL
;
p_sdp
->
i_media
=
0
;
p_sdp
->
i_attributes
=
0
;
p_sdp
->
pp_attributes
=
NULL
;
/* Search begin of field */
while
(
*
p_packet
==
'\r'
||
*
p_packet
==
'\n'
||
*
p_packet
==
' '
||
*
p_packet
==
'\t'
)
while
(
*
psz_sdp
!=
'\0'
)
{
char
*
psz_eol
;
while
(
*
psz_sdp
==
'\r'
||
*
psz_sdp
==
'\n'
||
*
psz_sdp
==
' '
||
*
psz_sdp
==
'\t'
)
{
p
_packet
++
;
p
sz_sdp
++
;
}
/* search end of line */
if
(
(
psz_e
nd
=
strchr
(
p_packet
,
'\n'
)
)
==
NULL
)
if
(
(
psz_e
ol
=
strchr
(
psz_sdp
,
'\n'
)
)
==
NULL
)
{
psz_e
nd
=
p_packet
+
strlen
(
p_packet
);
psz_e
ol
=
psz_sdp
+
strlen
(
psz_sdp
);
}
if
(
psz_e
nd
>
p_packet
&&
*
(
psz_end
-
1
)
==
'\r'
)
if
(
psz_e
ol
>
psz_sdp
&&
*
(
psz_eol
-
1
)
==
'\r'
)
{
psz_e
nd
--
;
psz_e
ol
--
;
}
if
(
psz_e
nd
<=
p_packet
)
if
(
psz_e
ol
<=
psz_sdp
)
{
break
;
}
*
psz_e
nd
++
=
'\0'
;
*
psz_e
ol
++
=
'\0'
;
if
(
p_packet
[
1
]
!=
'='
)
/* no space allowed between fields */
if
(
psz_sdp
[
1
]
!=
'='
)
{
msg_Warn
(
p_
parent
,
"invalid packet"
)
;
free_sd
(
sd
);
msg_Warn
(
p_
obj
,
"invalid packet"
)
;
/* MEMLEAK ! */
return
NULL
;
}
switch
(
p_packet
[
0
]
)
/* Now parse each line */
switch
(
psz_sdp
[
0
]
)
{
case
(
'v'
):
sd
->
i_version
=
atoi
(
&
p_packet
[
2
]
);
break
;
case
(
's'
):
sd
->
psz_sessionname
=
strdup
(
&
p_packet
[
2
]
);
p_sdp
->
psz_sessionname
=
strdup
(
&
psz_sdp
[
2
]
);
break
;
case
(
'o'
):
case
(
'i'
):
...
...
@@ -1029,87 +972,69 @@ static sess_descr_t * parse_sdp( vlc_object_t * p_parent, char *p_packet )
case
(
't'
):
case
(
'r'
):
break
;
case
(
'a'
):
case
(
'a'
):
/* attribute */
{
char
*
psz_eof
=
strchr
(
&
p_packet
[
2
],
':'
);
char
*
psz_eon
=
strchr
(
&
psz_sdp
[
2
],
':'
);
attribute_t
*
p_attr
=
(
attribute_t
*
)
malloc
(
sizeof
(
attribute_t
)
);
if
(
psz_eof
&&
psz_eof
[
1
]
!=
'\0'
)
/* Attribute with value */
if
(
psz_eon
)
{
attr_descr_t
*
attr
=
malloc
(
sizeof
(
attr_descr_t
)
)
;
*
psz_eon
++
=
'\0'
;
*
psz_eof
++
=
'\0'
;
p_attr
->
psz_field
=
strdup
(
&
psz_sdp
[
2
]
);
p_attr
->
psz_value
=
strdup
(
psz_eon
);
}
else
/* Attribute without value */
{
p_attr
->
psz_field
=
strdup
(
&
psz_sdp
[
2
]
);
p_attr
->
psz_value
=
NULL
;
}
attr
->
psz_field
=
strdup
(
&
p_packet
[
2
]
);
attr
->
psz_value
=
strdup
(
psz_eof
);
TAB_APPEND
(
p_sdp
->
i_attributes
,
p_sdp
->
pp_attributes
,
p_attr
);
break
;
}
TAB_APPEND
(
sd
->
i_attributes
,
sd
->
pp_attributes
,
attr
);
case
(
'm'
):
/* Media announcement */
{
/* If we have several medias, we pass the announcement to
* LIVE.COM, so just count them */
p_sdp
->
i_media
++
;
if
(
p_sdp
->
i_media
==
1
)
{
p_sdp
->
psz_media
=
strdup
(
&
psz_sdp
[
2
]
);
}
break
;
}
case
(
'
m
'
):
case
(
'
c
'
):
{
media_descr_t
*
media
=
malloc
(
sizeof
(
media_descr_t
)
);
media
->
psz_medianame
=
strdup
(
&
p_packet
[
2
]
);
media
->
psz_mediaconnection
=
NULL
;
if
(
p_sdp
->
i_media
>
1
)
break
;
TAB_APPEND
(
sd
->
i_media
,
sd
->
pp_media
,
media
);
p_sdp
->
psz_connection
=
strdup
(
&
psz_sdp
[
2
]
);
break
;
}
case
(
'c'
):
if
(
sd
->
i_media
<=
0
)
{
sd
->
psz_connection
=
strdup
(
&
p_packet
[
2
]
);
}
else
{
sd
->
pp_media
[
sd
->
i_media
-
1
]
->
psz_mediaconnection
=
strdup
(
&
p_packet
[
2
]
);
}
break
;
default:
break
;
}
p
_packet
=
psz_end
;
p
sz_sdp
=
psz_eol
;
}
return
sd
;
return
p_sdp
;
}
#define FREE( p ) \
if( p ) { free( p ); (p) = NULL; }
static
void
free_sd
(
sess_descr_t
*
p_sd
)
{
int
i
;
FREE
(
p_sd
->
psz_sessionname
);
FREE
(
p_sd
->
psz_connection
);
FREE
(
p_sd
->
psz_sdp
);
for
(
i
=
0
;
i
<
p_sd
->
i_media
;
i
++
)
{
FREE
(
p_sd
->
pp_media
[
i
]
->
psz_medianame
);
FREE
(
p_sd
->
pp_media
[
i
]
->
psz_mediaconnection
);
FREE
(
p_sd
->
pp_media
[
i
]
);
}
for
(
i
=
0
;
i
<
p_sd
->
i_attributes
;
i
++
)
{
FREE
(
p_sd
->
pp_attributes
[
i
]
->
psz_field
);
FREE
(
p_sd
->
pp_attributes
[
i
]
->
psz_value
);
FREE
(
p_sd
->
pp_attributes
[
i
]
);
}
FREE
(
p_sd
->
pp_attributes
);
FREE
(
p_sd
->
pp_media
);
free
(
p_sd
);
}
/***********************************************************************
* ismult: returns true if we have a multicast address
***********************************************************************/
static
int
ismult
(
char
*
psz_uri
)
{
char
*
psz_end
;
...
...
@@ -1132,113 +1057,40 @@ static int ismult( char *psz_uri )
return
(
i_value
<
224
?
VLC_FALSE
:
VLC_TRUE
);
}
/*****************************************************************************
* NetRead: read on a file descriptor, checking b_die periodically
*****************************************************************************
* Taken from net.c
* Code duplication because of select(). We need a net_Select() but that's
* quite difficult.
*****************************************************************************/
static
ssize_t
NetRead
(
intf_thread_t
*
p_intf
,
int
fd
[
2
],
uint8_t
*
p_buffer
,
int
i_len
)
static
int
InitSocket
(
intf_thread_t
*
p_intf
,
char
*
psz_address
,
int
i_port
)
{
#ifdef UNDER_CE
return
-
1
;
#else
struct
timeval
timeout
;
fd_set
fds
;
int
i_ret
;
int
i_handle_max
=
__MAX
(
fd
[
0
],
fd
[
1
]
);
/* Initialize file descriptor set */
FD_ZERO
(
&
fds
);
if
(
fd
[
0
]
>
0
)
FD_SET
(
fd
[
0
],
&
fds
);
if
(
fd
[
1
]
>
0
)
FD_SET
(
fd
[
1
],
&
fds
);
/* We'll wait 0.5 second if nothing happens */
timeout
.
tv_sec
=
0
;
timeout
.
tv_usec
=
500000
;
int
i_fd
=
net_OpenUDP
(
p_intf
,
psz_address
,
i_port
,
""
,
0
);
/* Find if some data is available */
i_ret
=
select
(
i_handle_max
+
1
,
&
fds
,
NULL
,
NULL
,
&
timeout
);
if
(
i_ret
==
-
1
&&
errno
!=
EINTR
)
{
msg_Err
(
p_intf
,
"network select error (%s)"
,
strerror
(
errno
)
);
}
else
if
(
i_ret
>
0
)
if
(
i_fd
!=
-
1
)
{
if
(
fd
[
0
]
>
0
&&
FD_ISSET
(
fd
[
0
],
&
fds
)
)
{
return
recv
(
fd
[
0
],
p_buffer
,
i_len
,
0
);
}
else
if
(
fd
[
1
]
>
0
&&
FD_ISSET
(
fd
[
1
],
&
fds
)
)
{
return
recv
(
fd
[
1
],
p_buffer
,
i_len
,
0
);
}
INSERT_ELEM
(
p_intf
->
p_sys
->
pi_fd
,
p_intf
->
p_sys
->
i_fd
,
p_intf
->
p_sys
->
i_fd
,
i_fd
);
return
VLC_SUCCESS
;
}
return
0
;
#endif
return
VLC_EGENERIC
;
}
/*
* This submodule is temporary and has a very high duplicate code rate
* This needs to be removed when SDP UDP parsing is fixed in liveMedia
*/
static
int
OpenSDP
(
vlc_object_t
*
p_this
)
#ifdef HAVE_ZLIB_H
static
int
Decompress
(
unsigned
char
*
psz_src
,
unsigned
char
**
_dst
,
int
i_len
)
{
demux_t
*
p_demux
=
(
demux_t
*
)
p_this
;
uint8_t
*
p_peek
;
if
(
p_demux
->
s
)
{
/* See if it looks like a SDP
v, o, s fields are mandatory and in this order */
if
(
stream_Peek
(
p_demux
->
s
,
&
p_peek
,
7
)
<
7
)
{
msg_Err
(
p_demux
,
"cannot peek"
);
return
VLC_EGENERIC
;
}
if
(
strncmp
(
(
char
*
)
p_peek
,
"v=0
\r\n
"
,
5
)
&&
strncmp
(
(
char
*
)
p_peek
,
"v=0
\n
"
,
4
)
&&
(
p_peek
[
0
]
<
'a'
||
p_peek
[
0
]
>
'z'
||
p_peek
[
1
]
!=
'='
)
)
{
msg_Warn
(
p_demux
,
"SDP (UDP) module discarded"
);
return
VLC_EGENERIC
;
}
}
p_demux
->
pf_control
=
Control
;
p_demux
->
pf_demux
=
Demux
;
int
i_result
,
i_dstsize
,
n
;
unsigned
char
*
psz_dst
;
z_stream
d_stream
;
return
VLC_SUCCESS
;
}
d_stream
.
zalloc
=
(
alloc_func
)
0
;
d_stream
.
zfree
=
(
free_func
)
0
;
d_stream
.
opaque
=
(
voidpf
)
0
;
/*****************************************************************************
* Demux: reads and demuxes data packets
* This submodule is temporary and has a very high duplicate code rate
* This needs to be removed when SDP UDP parsing is fixed in liveMedia
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, 1 otherwise
*****************************************************************************/
static
int
Demux
(
demux_t
*
p_demux
)
{
sess_descr_t
*
p_sd
=
NULL
;
playlist_t
*
p_playlist
=
NULL
;
int
i_sdp
=
0
;
int
i_sdp_max
=
1000
;
int
i_position
=
-
1
;
char
*
p_sdp
=
(
uint8_t
*
)
malloc
(
i_sdp_max
);
p_playlist
=
vlc_object_find
(
p_demux
,
VLC_OBJECT_PLAYLIST
,
FIND_ANYWHERE
);
if
(
!
p_playlist
)
i_result
=
inflateInit
(
&
d_stream
);
if
(
i_result
!=
Z_OK
)
{
msg_Err
(
p_demux
,
"can't find playlist"
);
return
-
1
;
printf
(
"inflateInit() failed. Result: %d
\n
"
,
i_result
);
return
(
-
1
)
;
}
#if 0
p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
i_position = p_playlist->i_index;
...
...
@@ -1246,195 +1098,51 @@ static int Demux( demux_t *p_demux )
for( ;; )
{
int i_read = stream_Read( p_demux->s, &p_sdp[i_sdp], i_sdp_max - i_sdp - 1 );
#endif
d_stream
.
next_in
=
(
Bytef
*
)
psz_src
;
d_stream
.
avail_in
=
i_len
;
n
=
0
;
if
(
i_read
<
0
)
{
msg_Err
(
p_demux
,
"failed to read SDP"
);
return
VLC_EGENERIC
;
}
psz_dst
=
NULL
;
i_sdp
+=
i_read
;
do
{
n
++
;
psz_dst
=
(
unsigned
char
*
)
realloc
(
psz_dst
,
n
*
1000
);
d_stream
.
next_out
=
(
Bytef
*
)
&
psz_dst
[(
n
-
1
)
*
1000
];
d_stream
.
avail_out
=
1000
;
if
(
i_read
<
i_sdp_max
-
i_sdp
-
1
)
i_result
=
inflate
(
&
d_stream
,
Z_NO_FLUSH
);
if
(
(
i_result
!=
Z_OK
)
&&
(
i_result
!=
Z_STREAM_END
)
)
{
p
_sdp
[
i_sdp
]
=
'\0'
;
break
;
p
rintf
(
"Zlib decompression failed. Result: %d
\n
"
,
i_result
)
;
return
(
-
1
)
;
}
i_sdp_max
+=
1000
;
p_sdp
=
(
uint8_t
*
)
realloc
(
p_sdp
,
i_sdp_max
);
}
while
(
(
d_stream
.
avail_out
==
0
)
&&
(
d_stream
.
avail_in
!=
0
)
&&
(
i_result
!=
Z_STREAM_END
)
);
msg_Dbg
(
p_demux
,
"sdp=%s
\n
"
,
p_sdp
);
p_sd
=
parse_sdp
(
(
vlc_object_t
*
)
p_demux
,
p_sdp
);
if
(
p_sd
)
{
char
*
psz_uri
,
*
psz_proto
,
*
psz_item_uri
;
char
*
psz_port
;
char
*
psz_uri_default
;
int
i_count
,
i
,
i_id
=
0
;
vlc_bool_t
b_http
=
VLC_FALSE
;
char
*
psz_http_path
=
NULL
;
playlist_item_t
*
p_item
;
psz_uri_default
=
NULL
;
if
(
p_sd
->
i_media
>
1
||
!
config_GetInt
(
p_demux
,
"sap-parse"
)
)
{
/* Let another module try this */
asprintf
(
&
psz_uri
,
"sdp://%s"
,
p_sd
->
psz_sdp
);
i_id
=
playlist_Add
(
p_playlist
,
psz_uri
,
p_sd
->
psz_sessionname
,
PLAYLIST_CHECK_INSERT
,
i_position
);
free
(
psz_uri
);
vlc_object_release
(
p_playlist
);
return
0
;
}
/* We try to parse it ourselves */
cfield_parse
(
p_sd
->
psz_connection
,
&
psz_uri_default
);
for
(
i_count
=
0
;
i_count
<
p_sd
->
i_media
;
i_count
++
)
{
int
i_group
=
0
;
int
i_packetsize
=
config_GetInt
(
p_demux
,
"mtu"
);
/* Build what we have to put in psz_item_uri, with the m and
* c fields */
if
(
!
p_sd
->
pp_media
[
i_count
]
)
{
vlc_object_release
(
p_playlist
);
return
-
1
;
}
mfield_parse
(
p_sd
->
pp_media
[
i_count
]
->
psz_medianame
,
&
psz_proto
,
&
psz_port
);
if
(
!
psz_proto
||
!
psz_port
)
{
vlc_object_release
(
p_playlist
);
return
-
1
;
}
if
(
p_sd
->
pp_media
[
i_count
]
->
psz_mediaconnection
)
{
cfield_parse
(
p_sd
->
pp_media
[
i_count
]
->
psz_mediaconnection
,
&
psz_uri
);
}
else
{
psz_uri
=
psz_uri_default
;
}
if
(
psz_uri
==
NULL
)
{
vlc_object_release
(
p_playlist
);
return
-
1
;
}
for
(
i
=
0
;
i
<
p_sd
->
i_attributes
;
i
++
)
{
if
(
!
strcasecmp
(
p_sd
->
pp_attributes
[
i
]
->
psz_field
,
"type"
)
&&
strstr
(
p_sd
->
pp_attributes
[
i
]
->
psz_value
,
"http"
)
)
{
b_http
=
VLC_TRUE
;
}
if
(
!
strcasecmp
(
p_sd
->
pp_attributes
[
i
]
->
psz_field
,
"http-path"
)
)
{
psz_http_path
=
strdup
(
p_sd
->
pp_attributes
[
i
]
->
psz_value
);
}
if
(
(
!
strcasecmp
(
p_sd
->
pp_attributes
[
i
]
->
psz_field
,
"plgroup"
)
)
||
(
!
strcasecmp
(
p_sd
->
pp_attributes
[
i
]
->
psz_field
,
"x-plgroup"
)
)
)
{
int
i_group_id
;
i_group_id
=
playlist_GroupToId
(
p_playlist
,
p_sd
->
pp_attributes
[
i
]
->
psz_value
);
if
(
i_group_id
!=
0
)
{
i_group
=
i_group_id
;
}
else
{
playlist_group_t
*
p_group
=
playlist_CreateGroup
(
p_playlist
,
p_sd
->
pp_attributes
[
i
]
->
psz_value
);
i_group
=
p_group
->
i_id
;
}
}
if
(
!
strcasecmp
(
p_sd
->
pp_attributes
[
i
]
->
psz_field
,
"packetsize"
)
)
{
i_packetsize
=
strtol
(
p_sd
->
pp_attributes
[
i
]
->
psz_value
,
NULL
,
10
);
}
}
/* Filling psz_uri */
if
(
b_http
==
VLC_FALSE
)
{
if
(
ismult
(
psz_uri
)
)
{
asprintf
(
&
psz_item_uri
,
"%s://@%s:%s"
,
psz_proto
,
psz_uri
,
psz_port
);
}
else
{
asprintf
(
&
psz_item_uri
,
"%s://%s:%s"
,
psz_proto
,
psz_uri
,
psz_port
);
}
}
else
{
if
(
psz_http_path
==
NULL
)
{
psz_http_path
=
strdup
(
"/"
);
}
if
(
*
psz_http_path
==
'/'
)
{
asprintf
(
&
psz_item_uri
,
"%s://%s:%s%s"
,
psz_proto
,
psz_uri
,
psz_port
,
psz_http_path
);
}
else
{
asprintf
(
&
psz_item_uri
,
"%s://%s:%s/%s"
,
psz_proto
,
psz_uri
,
psz_port
,
psz_http_path
);
}
if
(
psz_http_path
)
{
free
(
psz_http_path
);
}
}
i_dstsize
=
d_stream
.
total_out
;
inflateEnd
(
&
d_stream
);
/* Add the item in the playlist */
p_item
=
playlist_ItemNew
(
p_demux
,
psz_item_uri
,
p_sd
->
psz_sessionname
);
*
_dst
=
(
unsigned
char
*
)
realloc
(
psz_dst
,
i_dstsize
);
if
(
p_item
)
{
playlist_ItemSetGroup
(
p_item
,
i_group
);
if
(
i_packetsize
>
config_GetInt
(
p_demux
,
"mtu"
)
)
{
char
*
psz_packetsize_option
;
asprintf
(
&
psz_packetsize_option
,
"mtu=%i"
,
i_packetsize
);
playlist_ItemAddOption
(
p_item
,
psz_packetsize_option
);
free
(
psz_packetsize_option
);
}
playlist_AddItem
(
p_playlist
,
p_item
,
PLAYLIST_CHECK_INSERT
,
i_position
);
}
return
i_dstsize
;
}
#endif
free
(
psz_item_uri
);
}
static
int
RemoveAnnounce
(
intf_thread_t
*
p_intf
,
sap_announce_t
*
p_announce
)
{
msg_Err
(
p_intf
,
"remove not implemented"
);
return
VLC_SUCCESS
;
}
free_sd
(
p_sd
);
}
vlc_object_release
(
p_playlist
);
return
0
;
}
static
int
Control
(
demux_t
*
p_demux
,
int
i_query
,
va_list
args
)
static
void
CacheLoad
(
intf_thread_t
*
p_intf
)
{
return
VLC_EGENERIC
;
msg_Warn
(
p_intf
,
"Cache not implemented"
)
;
}
static
void
CloseSDP
(
vlc_object_t
*
p_this
)
static
void
CacheSave
(
intf_thread_t
*
p_intf
)
{
msg_Warn
(
p_intf
,
"Cache not implemented"
)
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment