[vlc-commits] [Git][videolan/vlc][master] 4 commits: sout/udp: add module for TS over raw UDP
Rémi Denis-Courmont (@Courmisch)
gitlab at videolan.org
Wed Dec 1 21:41:17 UTC 2021
Rémi Denis-Courmont pushed to branch master at VideoLAN / VLC
Commits:
9dec8f3b by Rémi Denis-Courmont at 2021-12-01T20:01:08+00:00
sout/udp: add module for TS over raw UDP
This module does not pretend that UDP output is a regular access that
should be handled with the "standard" stream output.
This takes handles SAP much more cleanly and supports vector I/O to
avoid unnecessary memory copies.
Also fixes #26058.
- - - - -
3d0da8e9 by Rémi Denis-Courmont at 2021-12-01T20:01:08+00:00
sout/udp: add backward compability
- - - - -
1315eb16 by Rémi Denis-Courmont at 2021-12-01T20:01:08+00:00
standard: remove udp handling
- - - - -
c142d02b by Rémi Denis-Courmont at 2021-12-01T20:01:08+00:00
udp access out: remove no longer used module
- - - - -
7 changed files:
- NEWS
- modules/access_output/Makefile.am
- − modules/access_output/udp.c
- modules/stream_out/Makefile.am
- modules/stream_out/standard.c
- + modules/stream_out/udp.c
- po/POTFILES.in
Changes:
=====================================
NEWS
=====================================
@@ -92,6 +92,10 @@ Stream output:
* New SDI output with improved audio and ancillary support.
Candidate for deprecation of decklink vout/aout modules.
* Support for DLNA/UPNP renderers
+ * The "udp" access output module has been removed.
+ Please use the UDP stream output instead, e.g.:
+ Old: '#std{access=udp,mux=ts,dst=239.255.1.2:1234,sap}'
+ New: '#udp{dst=239.255.1.2:1234,sap}'
Muxers:
* MP4 files are no longer faststart by default
=====================================
modules/access_output/Makefile.am
=====================================
@@ -3,14 +3,11 @@ access_outdir = $(pluginsdir)/access_output
libaccess_output_dummy_plugin_la_SOURCES = access_output/dummy.c
libaccess_output_file_plugin_la_SOURCES = access_output/file.c
libaccess_output_http_plugin_la_SOURCES = access_output/http.c
-libaccess_output_udp_plugin_la_SOURCES = access_output/udp.c
-libaccess_output_udp_plugin_la_LIBADD = $(SOCKET_LIBS)
access_out_LTLIBRARIES = \
libaccess_output_dummy_plugin.la \
libaccess_output_file_plugin.la \
- libaccess_output_http_plugin.la \
- libaccess_output_udp_plugin.la
+ libaccess_output_http_plugin.la
libaccess_output_livehttp_plugin_la_SOURCES = access_output/livehttp.c
libaccess_output_livehttp_plugin_la_CFLAGS = $(AM_CFLAGS) $(GCRYPT_CFLAGS)
=====================================
modules/access_output/udp.c deleted
=====================================
@@ -1,420 +0,0 @@
-/*****************************************************************************
- * udp.c
- *****************************************************************************
- * Copyright (C) 2001-2007 VLC authors and VideoLAN
- *
- * Authors: Laurent Aimar <fenrir at via.ecp.fr>
- * Eric Petit <titer at videolan.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <vlc_common.h>
-#include <vlc_plugin.h>
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <vlc_queue.h>
-#include <vlc_sout.h>
-#include <vlc_block.h>
-
-#ifdef _WIN32
-# include <winsock2.h>
-# include <ws2tcpip.h>
-#elif defined (HAVE_SYS_SOCKET_H)
-# include <sys/socket.h>
-#endif
-
-#include <vlc_network.h>
-
-#define MAX_EMPTY_BLOCKS 200
-
-/*****************************************************************************
- * Module descriptor
- *****************************************************************************/
-static int Open ( vlc_object_t * );
-static void Close( vlc_object_t * );
-
-#define SOUT_CFG_PREFIX "sout-udp-"
-
-#define CACHING_TEXT N_("Caching value (ms)")
-#define CACHING_LONGTEXT N_( \
- "Default caching value for outbound UDP streams. This " \
- "value should be set in milliseconds." )
-
-#define GROUP_TEXT N_("Group packets")
-#define GROUP_LONGTEXT N_("Packets can be sent one by one at the right time " \
- "or by groups. You can choose the number " \
- "of packets that will be sent at a time. It " \
- "helps reducing the scheduling load on " \
- "heavily-loaded systems." )
-
-vlc_module_begin ()
- set_description( N_("UDP stream output") )
- set_shortname( "UDP" )
- set_category( CAT_SOUT )
- set_subcategory( SUBCAT_SOUT_ACO )
- add_integer( SOUT_CFG_PREFIX "caching", DEFAULT_PTS_DELAY / 1000, CACHING_TEXT, CACHING_LONGTEXT )
- add_integer( SOUT_CFG_PREFIX "group", 1, GROUP_TEXT, GROUP_LONGTEXT )
-
- set_capability( "sout access", 0 )
- add_shortcut( "udp" )
- set_callbacks( Open, Close )
-vlc_module_end ()
-
-/*****************************************************************************
- * Exported prototypes
- *****************************************************************************/
-
-static const char *const ppsz_sout_options[] = {
- "caching",
- "group",
- NULL
-};
-
-/* Options handled by the libvlc network core */
-static const char *const ppsz_core_options[] = {
- "dscp",
- "ttl",
- "miface",
- NULL
-};
-
-static ssize_t Write ( sout_access_out_t *, block_t * );
-static int Control( sout_access_out_t *, int, va_list );
-
-static void* ThreadWrite( void * );
-
-typedef struct
-{
- vlc_tick_t i_caching;
- int i_handle;
- bool b_mtu_warning;
- bool dead;
- size_t i_mtu;
-
- vlc_queue_t queue;
- block_t *p_buffer;
-
- vlc_thread_t thread;
-} sout_access_out_sys_t;
-
-#define DEFAULT_PORT 1234
-
-/*****************************************************************************
- * Open: open the file
- *****************************************************************************/
-static int Open( vlc_object_t *p_this )
-{
- sout_access_out_t *p_access = (sout_access_out_t*)p_this;
- sout_access_out_sys_t *p_sys;
-
- char *psz_dst_addr = NULL;
- int i_dst_port;
-
- int i_handle;
-
- config_ChainParse( p_access, SOUT_CFG_PREFIX,
- ppsz_sout_options, p_access->p_cfg );
- config_ChainParse( p_access, "",
- ppsz_core_options, p_access->p_cfg );
-
- if (var_Create (p_access, "dst-port", VLC_VAR_INTEGER)
- || var_Create (p_access, "src-port", VLC_VAR_INTEGER)
- || var_Create (p_access, "dst-addr", VLC_VAR_STRING)
- || var_Create (p_access, "src-addr", VLC_VAR_STRING))
- {
- return VLC_ENOMEM;
- }
-
- if( !( p_sys = malloc ( sizeof( *p_sys ) ) ) )
- return VLC_ENOMEM;
- p_access->p_sys = p_sys;
-
- i_dst_port = DEFAULT_PORT;
- char *psz_parser = psz_dst_addr = strdup( p_access->psz_path );
- if( !psz_dst_addr )
- {
- free( p_sys );
- return VLC_ENOMEM;
- }
-
- if (psz_parser[0] == '[')
- psz_parser = strchr (psz_parser, ']');
-
- psz_parser = strchr (psz_parser ? psz_parser : psz_dst_addr, ':');
- if (psz_parser != NULL)
- {
- *psz_parser++ = '\0';
- i_dst_port = atoi (psz_parser);
- }
-
- i_handle = net_ConnectDgram( p_this, psz_dst_addr, i_dst_port, -1,
- IPPROTO_UDP );
- free (psz_dst_addr);
-
- if( i_handle == -1 )
- {
- msg_Err( p_access, "failed to create raw UDP socket" );
- free (p_sys);
- return VLC_EGENERIC;
- }
- else
- {
- char addr[NI_MAXNUMERICHOST];
- int port;
-
- if (net_GetSockAddress (i_handle, addr, &port) == 0)
- {
- msg_Dbg (p_access, "source: %s port %d", addr, port);
- var_SetString (p_access, "src-addr", addr);
- var_SetInteger (p_access, "src-port", port);
- }
-
- if (net_GetPeerAddress (i_handle, addr, &port) == 0)
- {
- msg_Dbg (p_access, "destination: %s port %d", addr, port);
- var_SetString (p_access, "dst-addr", addr);
- var_SetInteger (p_access, "dst-port", port);
- }
- }
- shutdown( i_handle, SHUT_RD );
-
- p_sys->i_caching = VLC_TICK_FROM_MS(
- var_GetInteger( p_access, SOUT_CFG_PREFIX "caching") );
- p_sys->i_handle = i_handle;
- p_sys->i_mtu = var_CreateGetInteger( p_this, "mtu" );
- p_sys->b_mtu_warning = false;
- p_sys->dead = false;
- vlc_queue_Init(&p_sys->queue, offsetof (block_t, p_next));
- p_sys->p_buffer = NULL;
-
- if( vlc_clone( &p_sys->thread, ThreadWrite, p_access,
- VLC_THREAD_PRIORITY_HIGHEST ) )
- {
- msg_Err( p_access, "cannot spawn sout access thread" );
- net_Close (i_handle);
- free (p_sys);
- return VLC_EGENERIC;
- }
-
- p_access->pf_write = Write;
- p_access->pf_control = Control;
-
- return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * Close: close the target
- *****************************************************************************/
-static void Close( vlc_object_t * p_this )
-{
- sout_access_out_t *p_access = (sout_access_out_t*)p_this;
- sout_access_out_sys_t *p_sys = p_access->p_sys;
-
- vlc_queue_Kill(&p_sys->queue, &p_sys->dead);
- vlc_join( p_sys->thread, NULL );
-
- if( p_sys->p_buffer ) block_Release( p_sys->p_buffer );
-
- net_Close( p_sys->i_handle );
- free( p_sys );
-}
-
-static int Control( sout_access_out_t *p_access, int i_query, va_list args )
-{
- (void)p_access;
-
- switch( i_query )
- {
- case ACCESS_OUT_CONTROLS_PACE:
- *va_arg( args, bool * ) = false;
- break;
-
- default:
- return VLC_EGENERIC;
- }
- return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * Write: standard write on a file descriptor.
- *****************************************************************************/
-static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
-{
- sout_access_out_sys_t *p_sys = p_access->p_sys;
- int i_len = 0;
-
- while( p_buffer )
- {
- block_t *p_next;
- int i_packets = 0;
- vlc_tick_t now = vlc_tick_now();
-
- if( !p_sys->b_mtu_warning && p_buffer->i_buffer > p_sys->i_mtu )
- {
- msg_Warn( p_access, "packet size > MTU, you should probably "
- "increase the MTU" );
- p_sys->b_mtu_warning = true;
- }
-
- /* Check if there is enough space in the buffer */
- if( p_sys->p_buffer &&
- p_sys->p_buffer->i_buffer + p_buffer->i_buffer > p_sys->i_mtu )
- {
- if( p_sys->p_buffer->i_dts + p_sys->i_caching < now )
- {
- msg_Dbg( p_access, "late packet for UDP input (%"PRId64 ")",
- now - p_sys->p_buffer->i_dts
- - p_sys->i_caching );
- }
- vlc_queue_Enqueue(&p_sys->queue, p_sys->p_buffer);
- p_sys->p_buffer = NULL;
- }
-
- i_len += p_buffer->i_buffer;
- while( p_buffer->i_buffer )
- {
- size_t i_payload_size = p_sys->i_mtu;
- size_t i_write = __MIN( p_buffer->i_buffer, i_payload_size );
-
- i_packets++;
-
- if( !p_sys->p_buffer )
- {
- p_sys->p_buffer = block_Alloc( p_sys->i_mtu );
- if( !p_sys->p_buffer ) break;
- p_sys->p_buffer->i_dts = p_buffer->i_dts;
- p_sys->p_buffer->i_buffer = 0;
- }
-
- memcpy( p_sys->p_buffer->p_buffer + p_sys->p_buffer->i_buffer,
- p_buffer->p_buffer, i_write );
-
- p_sys->p_buffer->i_buffer += i_write;
- p_buffer->p_buffer += i_write;
- p_buffer->i_buffer -= i_write;
- if ( p_buffer->i_flags & BLOCK_FLAG_CLOCK )
- {
- if ( p_sys->p_buffer->i_flags & BLOCK_FLAG_CLOCK )
- msg_Warn( p_access, "putting two PCRs at once" );
- p_sys->p_buffer->i_flags |= BLOCK_FLAG_CLOCK;
- }
-
- if( p_sys->p_buffer->i_buffer == p_sys->i_mtu || i_packets > 1 )
- {
- /* Flush */
- if( p_sys->p_buffer->i_dts + p_sys->i_caching < now )
- {
- msg_Dbg( p_access, "late packet for udp input (%"PRId64 ")",
- vlc_tick_now() - p_sys->p_buffer->i_dts
- - p_sys->i_caching );
- }
- vlc_queue_Enqueue(&p_sys->queue, p_sys->p_buffer);
- p_sys->p_buffer = NULL;
- }
- }
-
- p_next = p_buffer->p_next;
- block_Release( p_buffer );
- p_buffer = p_next;
- }
-
- return i_len;
-}
-
-/*****************************************************************************
- * ThreadWrite: Write a packet on the network at the good time.
- *****************************************************************************/
-static void* ThreadWrite( void *data )
-{
- sout_access_out_t *p_access = data;
- sout_access_out_sys_t *p_sys = p_access->p_sys;
- vlc_tick_t i_date_last = -1;
- const unsigned i_group = var_GetInteger( p_access,
- SOUT_CFG_PREFIX "group" );
- int i_to_send = i_group;
- unsigned i_dropped_packets = 0;
- block_t *p_pk;
-
- while ((p_pk = vlc_queue_DequeueKillable(&p_sys->queue,
- &p_sys->dead)) != NULL)
- {
- vlc_tick_t i_date;
-
- i_date = p_sys->i_caching + p_pk->i_dts;
- if( i_date_last > 0 )
- {
- if( i_date - i_date_last > VLC_TICK_FROM_SEC(2) )
- {
- if( !i_dropped_packets )
- msg_Dbg( p_access, "mmh, hole (%"PRId64" > 2s) -> drop",
- i_date - i_date_last );
-
- block_Release( p_pk );
-
- i_date_last = i_date;
- i_dropped_packets++;
- continue;
- }
- else if( i_date - i_date_last < VLC_TICK_FROM_MS(-1) )
- {
- if( !i_dropped_packets )
- msg_Dbg( p_access, "mmh, packets in the past (%"PRId64")",
- i_date_last - i_date );
- }
- }
-
- i_to_send--;
- if( !i_to_send || (p_pk->i_flags & BLOCK_FLAG_CLOCK) )
- {
- vlc_tick_wait( i_date );
- i_to_send = i_group;
- }
- if ( send( p_sys->i_handle, p_pk->p_buffer, p_pk->i_buffer, 0 ) == -1 )
- msg_Warn( p_access, "send error: %s", vlc_strerror_c(errno) );
-
- if( i_dropped_packets )
- {
- msg_Dbg( p_access, "dropped %i packets", i_dropped_packets );
- i_dropped_packets = 0;
- }
-
- i_date_last = i_date;
-
-#if 1
- i_date = vlc_tick_now() - i_date;
- if ( i_date > VLC_TICK_FROM_MS(20) )
- {
- msg_Dbg( p_access, "packet has been sent too late (%"PRId64 ")",
- i_date );
- }
-#endif
-
- block_Release( p_pk );
-
- }
- return NULL;
-}
=====================================
modules/stream_out/Makefile.am
=====================================
@@ -4,10 +4,8 @@ libstream_out_dummy_plugin_la_SOURCES = stream_out/dummy.c
libstream_out_cycle_plugin_la_SOURCES = stream_out/cycle.c
libstream_out_delay_plugin_la_SOURCES = stream_out/delay.c
libstream_out_stats_plugin_la_SOURCES = stream_out/stats.c
-libstream_out_standard_plugin_la_SOURCES = stream_out/standard.c \
- stream_out/sdp_helper.c stream_out/sdp_helper.h
+libstream_out_standard_plugin_la_SOURCES = stream_out/standard.c
libstream_out_standard_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS_access_output_srt)
-libstream_out_standard_plugin_la_LIBADD = $(SOCKET_LIBS)
libstream_out_duplicate_plugin_la_SOURCES = stream_out/duplicate.c
libstream_out_es_plugin_la_SOURCES = stream_out/es.c
libstream_out_display_plugin_la_SOURCES = stream_out/display.c
@@ -30,6 +28,10 @@ libstream_out_transcode_plugin_la_SOURCES = \
stream_out/transcode/audio.c stream_out/transcode/video.c
libstream_out_transcode_plugin_la_CFLAGS = $(AM_CFLAGS)
libstream_out_transcode_plugin_la_LIBADD = $(LIBM)
+libstream_out_udp_plugin_la_SOURCES = \
+ stream_out/sdp_helper.c stream_out/sdp_helper.h \
+ stream_out/udp.c
+libstream_out_udp_plugin_la_LIBADD = $(SOCKET_LIBS)
sout_LTLIBRARIES = \
libstream_out_dummy_plugin.la \
@@ -47,7 +49,8 @@ sout_LTLIBRARIES = \
libstream_out_record_plugin.la \
libstream_out_smem_plugin.la \
libstream_out_setid_plugin.la \
- libstream_out_transcode_plugin.la
+ libstream_out_transcode_plugin.la \
+ libstream_out_udp_plugin.la
if HAVE_DECKLINK
libstream_out_sdi_plugin_la_CXXFLAGS = $(AM_CXXFLAGS) $(CPPFLAGS_decklinkoutput)
=====================================
modules/stream_out/standard.c
=====================================
@@ -33,8 +33,6 @@
#include <vlc_network.h>
#include <vlc_url.h>
-#include <vlc_memstream.h>
-#include "sdp_helper.h"
/*****************************************************************************
* Module descriptor
@@ -56,16 +54,6 @@
#define PATH_LONGTEXT N_( \
"Filename for stream. "\
"Helper setting for dst, dst=bind+'/'+path. dst-parameter overrides this." )
-#define NAME_TEXT N_("Session name")
-#define NAME_LONGTEXT N_( \
- "This is the name of the session that will be announced in the SDP " \
- "(Session Descriptor)." )
-#define DESC_TEXT N_("Session description")
-#define DESC_LONGTEXT N_( \
- "This allows you to give a short description with details about the stream, " \
- "that will be announced in the SDP (Session Descriptor)." )
-#define SAP_TEXT N_("SAP announcing")
-#define SAP_LONGTEXT N_("Announce this session with SAP.")
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
@@ -82,7 +70,7 @@ vlc_module_begin ()
set_shortname( N_("Standard"))
set_description( N_("Standard stream output") )
set_capability( "sout output", 50 )
- add_shortcut( "standard", "std", "file", "http", "udp", SRT_SHORTCUT )
+ add_shortcut( "standard", "std", "file", "http", SRT_SHORTCUT )
set_category( CAT_SOUT )
set_subcategory( SUBCAT_SOUT_STREAM )
@@ -91,9 +79,9 @@ vlc_module_begin ()
add_string( SOUT_CFG_PREFIX "dst", "", DEST_TEXT, DEST_LONGTEXT )
add_string( SOUT_CFG_PREFIX "bind", "", BIND_TEXT, BIND_LONGTEXT )
add_string( SOUT_CFG_PREFIX "path", "", PATH_TEXT, PATH_LONGTEXT )
- add_bool( SOUT_CFG_PREFIX "sap", false, SAP_TEXT, SAP_LONGTEXT )
- add_string( SOUT_CFG_PREFIX "name", "", NAME_TEXT, NAME_LONGTEXT )
- add_string( SOUT_CFG_PREFIX "description", "", DESC_TEXT, DESC_LONGTEXT )
+ add_obsolete_bool( SOUT_CFG_PREFIX "sap" ) /* since 4.0.0 */
+ add_obsolete_string( SOUT_CFG_PREFIX "name" ) /* since 4.0.0 */
+ add_obsolete_string( SOUT_CFG_PREFIX "description" ) /* since 4.0.0 */
add_obsolete_string( SOUT_CFG_PREFIX "url" ) /* since 4.0.0 */
add_obsolete_string( SOUT_CFG_PREFIX "email" ) /* since 4.0.0 */
add_obsolete_string( SOUT_CFG_PREFIX "phone" ) /* since 3.0.0 */
@@ -107,12 +95,9 @@ vlc_module_end ()
*****************************************************************************/
static const char *const ppsz_sout_options[] = {
"access", "mux", "url", "dst",
- "sap", "name", "description",
"bind", "path", NULL
};
-#define DEFAULT_PORT 1234
-
typedef struct
{
sout_mux_t *p_mux;
@@ -144,57 +129,6 @@ static void Flush( sout_stream_t *p_stream, void *id )
sout_MuxFlush( p_sys->p_mux, (sout_input_t*)id );
}
-static void create_SDP(sout_stream_t *p_stream, sout_access_out_t *p_access)
-{
- sout_stream_sys_t *p_sys = p_stream->p_sys;
-
- static const struct addrinfo hints = {
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_DGRAM,
- .ai_protocol = 0,
- .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_IDN,
- };
- char *shost = var_GetNonEmptyString (p_access, "src-addr");
- char *dhost = var_GetNonEmptyString (p_access, "dst-addr");
- int sport = var_GetInteger (p_access, "src-port");
- int dport = var_GetInteger (p_access, "dst-port");
- struct sockaddr_storage src, dst;
- socklen_t srclen = 0, dstlen = 0;
- struct addrinfo *res;
-
- if (!vlc_getaddrinfo (dhost, dport, &hints, &res))
- {
- memcpy (&dst, res->ai_addr, dstlen = res->ai_addrlen);
- freeaddrinfo (res);
- }
-
- if (!vlc_getaddrinfo (shost, sport, &hints, &res))
- {
- memcpy (&src, res->ai_addr, srclen = res->ai_addrlen);
- freeaddrinfo (res);
- }
-
- struct vlc_memstream sdp;
-
- if (vlc_sdp_Start(&sdp, VLC_OBJECT (p_stream), SOUT_CFG_PREFIX,
- (struct sockaddr *)&src, srclen,
- (struct sockaddr *)&dst, dstlen) == 0)
- {
- vlc_memstream_printf(&sdp, "m=video %d udp mpeg\r\n", dport);
-
- /* Register the SDP with the SAP thread */
- if (vlc_memstream_close(&sdp) == 0)
- {
- msg_Dbg(p_stream, "Generated SDP:\n%s", sdp.ptr);
- p_sys->p_session =
- sout_AnnounceRegisterSDP(p_stream, sdp.ptr, dhost);
- free(sdp.ptr);
- }
- }
- free(shost);
- free(dhost);
-}
-
static const char *getMuxFromAlias( const char *psz_alias )
{
static struct { const char alias[6]; const char mux[32]; } mux_alias[] =
@@ -263,8 +197,6 @@ static int fixAccessMux( sout_stream_t *p_stream, char **ppsz_mux,
{
if( !strncmp( psz_access, "mmsh", 4 ) )
*ppsz_mux = strdup("asfh");
- else if (!strcmp (psz_access, "udp"))
- *ppsz_mux = strdup("ts");
else if( psz_mux_byext )
*ppsz_mux = strdup(psz_mux_byext);
else
@@ -301,18 +233,6 @@ static void checkAccessMux( sout_stream_t *p_stream, char *psz_access,
else if( !exactMatch( psz_access, "file", 4 ) &&
( exactMatch( psz_mux, "mov", 3 ) || exactMatch( psz_mux, "mp4", 3 ) ) )
msg_Err( p_stream, "mov and mp4 mux are only valid with file output" );
- else if( exactMatch( psz_access, "udp", 3 ) )
- {
- if( exactMatch( psz_mux, "ffmpeg", 6 ) || exactMatch( psz_mux, "avformat", 8 ) )
- { /* why would you use ffmpeg's ts muxer ? YOU DON'T LOVE VLC ??? */
- char *psz_ffmpeg_mux = var_CreateGetString( p_stream, "sout-avformat-mux" );
- if( !psz_ffmpeg_mux || strncmp( psz_ffmpeg_mux, "mpegts", 6 ) )
- msg_Err( p_stream, "UDP output is only valid with TS mux" );
- free( psz_ffmpeg_mux );
- }
- else if( !exactMatch( psz_mux, "ts", 2 ) )
- msg_Err( p_stream, "UDP output is only valid with TS mux" );
- }
}
static int Control(sout_stream_t *stream, int query, va_list args)
@@ -418,9 +338,6 @@ static int Open( vlc_object_t *p_this )
}
}
- if( var_GetBool( p_stream, SOUT_CFG_PREFIX"sap" ) )
- create_SDP( p_stream, p_access );
-
p_stream->ops = &ops;
ret = VLC_SUCCESS;
msg_Dbg( p_this, "using `%s/%s://%s'", psz_access, psz_mux, psz_url );
=====================================
modules/stream_out/udp.c
=====================================
@@ -0,0 +1,365 @@
+/*****************************************************************************
+ * udp.c: standard stream output module
+ *****************************************************************************
+ * Copyright (C) 2003-2011 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include <vlc_common.h>
+#include <vlc_block.h>
+#include <vlc_plugin.h>
+#include <vlc_sout.h>
+
+#include <vlc_network.h>
+#include <vlc_memstream.h>
+#include "sdp_helper.h"
+
+struct sout_stream_udp
+{
+ sout_access_out_t *access;
+ sout_mux_t *mux;
+ session_descriptor_t *sap;
+ int fd;
+ uint_fast16_t mtu;
+};
+
+static void *Add(sout_stream_t *stream, const es_format_t *fmt)
+{
+ struct sout_stream_udp *sys = stream->p_sys;
+
+ return sout_MuxAddStream(sys->mux, fmt);
+}
+
+static void Del(sout_stream_t *stream, void *id)
+{
+ struct sout_stream_udp *sys = stream->p_sys;
+
+ sout_MuxDeleteStream(sys->mux, id);
+}
+
+static int Send(sout_stream_t *stream, void *id, block_t *block)
+{
+ struct sout_stream_udp *sys = stream->p_sys;
+
+ return sout_MuxSendBuffer(sys->mux, id, block);
+}
+
+static void Flush(sout_stream_t *stream, void *id)
+{
+ struct sout_stream_udp *sys = stream->p_sys;
+
+ sout_MuxFlush(sys->mux, id);
+}
+
+#define SOUT_CFG_PREFIX "sout-udp-"
+
+static session_descriptor_t *CreateSDP(vlc_object_t *obj, int fd)
+{
+ union {
+ struct sockaddr addr;
+ struct sockaddr_in in;
+ struct sockaddr_in6 in6;
+ } src, dst;
+ socklen_t srclen = sizeof (srclen), dstlen = sizeof (dst);
+ char dhost[INET6_ADDRSTRLEN];
+ unsigned short dport;
+
+ if (getsockname(fd, &src.addr, &srclen)
+ || getpeername(fd, &dst.addr, &dstlen)) {
+ int val = errno;
+
+ msg_Err(obj, "cannot format SDP: %s", vlc_strerror_c(val));
+ return NULL;
+ }
+
+ switch (dst.addr.sa_family) {
+ case AF_INET:
+ inet_ntop(AF_INET, &dst.in.sin_addr, dhost, sizeof (dhost));
+ dport = dst.in.sin_port;
+ break;
+ case AF_INET6:
+ inet_ntop(AF_INET6, &dst.in6.sin6_addr, dhost, sizeof (dhost));
+ dport = dst.in6.sin6_port;
+ break;
+ default:
+ return NULL;
+ }
+
+ struct vlc_memstream sdp;
+
+ if (vlc_sdp_Start(&sdp, obj, SOUT_CFG_PREFIX,
+ &src.addr, srclen, &dst.addr, dstlen))
+ return NULL;
+
+ vlc_memstream_printf(&sdp, "m=video %d udp mpeg\r\n", ntohs(dport));
+
+ if (vlc_memstream_close(&sdp) != 0)
+ return NULL;
+
+ /* Register the SDP with the SAP thread */
+ session_descriptor_t *session;
+
+ msg_Dbg(obj, "Generated SDP:\n%s", sdp.ptr);
+ session = sout_AnnounceRegisterSDP(obj, sdp.ptr, dhost);
+ free(sdp.ptr);
+ return session;
+}
+
+static int Control(sout_stream_t *stream, int query, va_list args)
+{
+ switch (query) {
+ case SOUT_STREAM_IS_SYNCHRONOUS:
+ *va_arg(args, bool *) = true;
+ break;
+
+ default:
+ return VLC_EGENERIC;
+ }
+
+ (void) stream;
+ return VLC_SUCCESS;
+}
+
+static ssize_t AccessOutWrite(sout_access_out_t *access, block_t *block)
+{
+ struct sout_stream_udp *sys = access->p_sys;
+ ssize_t total = 0;
+
+ while (block != NULL) {
+ struct iovec iov[16];
+ block_t *unsent = block;
+ unsigned iovlen = 0;
+ size_t tosend = 0;
+
+ /* Count how many blocks to gather */
+ do {
+ if (iovlen >= ARRAY_SIZE(iov))
+ break;
+ if (unsent->i_buffer + tosend > sys->mtu && likely(iovlen > 0))
+ break;
+
+ iov[iovlen].iov_base = unsent->p_buffer;
+ iov[iovlen].iov_len = unsent->i_buffer;
+ iovlen++;
+ tosend += unsent->i_buffer;
+ unsent = unsent->p_next;
+ } while (unsent != NULL);
+
+ /* Send */
+ struct msghdr hdr = { .msg_iov = iov, .msg_iovlen = iovlen };
+ int val = sendmsg(sys->fd, &hdr, 0);
+
+ if (val < 0)
+ msg_Err(access, "send error: %s", vlc_strerror_c(errno));
+ else
+ total += val;
+
+ /* Free */
+ do {
+ block_t *next = block->p_next;
+
+ block_Release(block);
+ block = next;
+ } while (block != unsent);
+ }
+
+ return total;
+}
+
+static void Close(vlc_object_t *obj)
+{
+ sout_stream_t *stream = (sout_stream_t *)obj;
+ struct sout_stream_udp *sys = stream->p_sys;
+
+ if (sys->sap != NULL)
+ sout_AnnounceUnRegister(stream, sys->sap);
+
+ sout_MuxDelete(sys->mux);
+ sout_AccessOutDelete(sys->access);
+ net_Close(sys->fd);
+ free(sys);
+}
+
+static const struct sout_stream_operations ops = {
+ Add, Del, Send, Control, Flush,
+};
+
+static const char *const chain_options[] = {
+ "avformat", "dst", "sap", "name", "description", NULL
+};
+
+#define DEFAULT_PORT 1234
+
+static int Open(vlc_object_t *obj)
+{
+ sout_stream_t *stream = (sout_stream_t *)obj;
+ sout_access_out_t *access = NULL;
+ const char *muxmod = "ts";
+ int ret;
+
+ /* --sout '#std{...}' option backward compatibility */
+ if (strcmp(stream->psz_name, "std") == 0
+ || strcmp(stream->psz_name, "standard") == 0) {
+ config_chain_t *c = NULL;
+
+ for (c = stream->p_cfg; c != NULL; c = c->p_next)
+ if (strcmp(c->psz_name, "access") == 0)
+ break;
+
+ if (c == NULL) /* default is file, not for us */
+ return VLC_ENOTSUP;
+ if (strcmp(c->psz_value, "udp"))
+ return VLC_ENOTSUP;
+
+ msg_Info(stream, "\"#standard{access=udp,mux=ts,...}\" is deprecated. "
+ "Use \"#udp{...}\" instead.");
+ }
+
+ config_ChainParse(stream, SOUT_CFG_PREFIX, chain_options, stream->p_cfg);
+
+ char *dst = var_GetNonEmptyString(stream, SOUT_CFG_PREFIX "dst");
+ if (dst == NULL) {
+ msg_Err(stream, "missing required destination");
+ return VLC_EINVAL;
+ }
+
+ const char *dhost;
+ char *end;
+ int dport = DEFAULT_PORT;
+
+ if (dst[0] == '[') {
+ dhost = dst;
+ end = strchr(dst, ']');
+
+ if (end != NULL)
+ *(end++) = '\0';
+ } else {
+ dhost = dst;
+ end = strchr(dst, ':');
+ }
+
+ if (end != NULL && *end == ':') {
+ *(end++) = '\0';
+ dport = atoi(&end[1]);
+ }
+
+ int fd = net_ConnectDgram(stream, dhost, dport, -1, IPPROTO_UDP);
+ free(dst);
+ if (fd == -1) {
+ int val = errno;
+
+ msg_Err(stream, "cannot reach destination: %s", vlc_strerror_c(val));
+ return val ? -val : VLC_EGENERIC;
+ }
+
+ if (var_GetBool(stream, SOUT_CFG_PREFIX "avformat")
+ && var_Create(stream, "sout-avformat-mux",
+ VLC_VAR_STRING) == VLC_SUCCESS) {
+ var_SetString(stream, "sout-avformat-mux", "mpegts");
+ muxmod = "avformat";
+ }
+
+ struct sout_stream_udp *sys = malloc(sizeof (*sys));
+ if (unlikely(sys == NULL)) {
+ ret = VLC_ENOMEM;
+ goto error;
+ }
+
+ access = vlc_object_create(stream, sizeof (*access));
+ if (unlikely(access == NULL)) {
+ ret = VLC_ENOMEM;
+ goto error;
+ }
+
+ access->p_module = NULL;
+ access->psz_access = strdup("udp");
+ access->psz_path = NULL;
+ access->p_sys = sys;
+ access->pf_seek = NULL;
+ access->pf_read = NULL;
+ access->pf_write = AccessOutWrite;
+ access->pf_control = NULL;
+ access->p_cfg = NULL;
+ sys->access = access;
+ sys->fd = fd;
+ sys->mtu = var_InheritInteger(stream, "mtu");
+
+ sout_mux_t *mux = sout_MuxNew(access, muxmod);
+ if (mux == NULL) {
+ ret = VLC_ENOTSUP;
+ goto error;
+ }
+ sys->mux = mux;
+
+ if (var_GetBool(stream, SOUT_CFG_PREFIX "sap"))
+ sys->sap = CreateSDP(VLC_OBJECT(stream), fd);
+ else
+ sys->sap = NULL;
+
+ stream->p_sys = sys;
+ stream->ops = &ops;
+ return VLC_SUCCESS;
+
+error:
+ if (access != NULL)
+ sout_AccessOutDelete(access);
+ free(sys);
+ net_Close(fd);
+ return ret;
+}
+
+#define AVF_TEXT N_("Use libavformat")
+#define AVF_LONGTEXT N_("Use libavformat instead of dvbpsi to mux MPEG TS.")
+#define DEST_TEXT N_("Destination")
+#define DEST_LONGTEXT N_( \
+ "Destination address and port (colon-separated) for the stream.")
+#define SAP_TEXT N_("SAP announcement")
+#define SAP_LONGTEXT N_("Announce this stream as a session with SAP.")
+#define NAME_TEXT N_("SAP name")
+#define NAME_LONGTEXT N_( \
+ "Name of the stream that will be announced with SAP.")
+#define DESC_TEXT N_("SAP description")
+#define DESC_LONGTEXT N_( \
+ "Short description of the stream that will be announced with SAP.")
+
+vlc_module_begin()
+ set_shortname(N_("UDP"))
+ set_description(N_("UDP stream output"))
+ set_capability("sout output", 40)
+ add_shortcut("standard", "std", "udp")
+ set_category(CAT_SOUT)
+ set_subcategory(SUBCAT_SOUT_STREAM)
+
+ add_bool(SOUT_CFG_PREFIX "avformat", false, AVF_TEXT, AVF_LONGTEXT)
+ add_string(SOUT_CFG_PREFIX "dst", "", DEST_TEXT, DEST_LONGTEXT)
+ add_bool(SOUT_CFG_PREFIX "sap", false, SAP_TEXT, SAP_LONGTEXT)
+ add_string(SOUT_CFG_PREFIX "name", "", NAME_TEXT, NAME_LONGTEXT)
+ add_string(SOUT_CFG_PREFIX "description", "", DESC_TEXT, DESC_LONGTEXT)
+
+ set_callbacks(Open, Close)
+vlc_module_end()
=====================================
po/POTFILES.in
=====================================
@@ -221,7 +221,6 @@ modules/access_output/livehttp.c
modules/access_output/rist.c
modules/access_output/shout.c
modules/access_output/srt.c
-modules/access_output/udp.c
modules/arm_neon/chroma_yuv.c
modules/arm_neon/volume.c
modules/arm_neon/yuv_rgb.c
@@ -1257,6 +1256,7 @@ modules/stream_out/smem.c
modules/stream_out/stats.c
modules/stream_out/standard.c
modules/stream_out/transcode/transcode.c
+modules/stream_out/udp.c
modules/text_renderer/freetype/fonts/fontconfig.c
modules/text_renderer/freetype/freetype.c
modules/text_renderer/nsspeechsynthesizer.m
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/82347d93d526df00c1ebf73805534b7f4081859a...c142d02bb4e37c58e07bda80fb4edd720c2b85e6
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/82347d93d526df00c1ebf73805534b7f4081859a...c142d02bb4e37c58e07bda80fb4edd720c2b85e6
You're receiving this email because of your account on code.videolan.org.
More information about the vlc-commits
mailing list