|
@@ -0,0 +1,394 @@
|
|
|
+From 5715c84484346241bc934ff139c268a044e40853 Mon Sep 17 00:00:00 2001
|
|
|
+From: Alexandre Janniaux <alexandre.janniaux@gmail.com>
|
|
|
+Date: Wed, 28 Nov 2018 18:27:16 +0100
|
|
|
+Subject: [PATCH] transcode: add support for mutliple venc parameters
|
|
|
+
|
|
|
+Add support for multiple venc parameters for transcoding. Venc
|
|
|
+parameters are tested in th given order and fallback if the encoder
|
|
|
+can't be opened.
|
|
|
+
|
|
|
+For example:
|
|
|
+--sout#transcode{\
|
|
|
+ venc={vcodec=h264,module=avcodec{...}},\
|
|
|
+ venc={vcodec=VP80,module=vpx{...}}}
|
|
|
+will first try avcodec module with h264 video format, then vpx module
|
|
|
+with VP8 video format.
|
|
|
+---
|
|
|
+ modules/codec/avcodec/encoder.c | 2 +
|
|
|
+ modules/stream_out/transcode/transcode.c | 257 ++++++++++++++++++-----
|
|
|
+ modules/stream_out/transcode/transcode.h | 2 +
|
|
|
+ 3 files changed, 206 insertions(+), 55 deletions(-)
|
|
|
+
|
|
|
+diff --git a/modules/codec/avcodec/encoder.c b/modules/codec/avcodec/encoder.c
|
|
|
+index c587e2b243..670d03d7ef 100644
|
|
|
+--- a/modules/codec/avcodec/encoder.c
|
|
|
++++ b/modules/codec/avcodec/encoder.c
|
|
|
+@@ -346,12 +346,14 @@ int InitVideoEnc( vlc_object_t *p_this )
|
|
|
+ if( !p_codec )
|
|
|
+ {
|
|
|
+ msg_Err( p_this, "Encoder `%s' not found", psz_encoder );
|
|
|
++ free( psz_encoder );
|
|
|
+ return VLC_EGENERIC;
|
|
|
+ }
|
|
|
+ else if( p_codec->id != i_codec_id )
|
|
|
+ {
|
|
|
+ msg_Err( p_this, "Encoder `%s' can't handle %4.4s",
|
|
|
+ psz_encoder, (char*)&p_enc->fmt_out.i_codec );
|
|
|
++ free( psz_encoder );
|
|
|
+ return VLC_EGENERIC;
|
|
|
+ }
|
|
|
+ }
|
|
|
+diff --git a/modules/stream_out/transcode/transcode.c b/modules/stream_out/transcode/transcode.c
|
|
|
+index c92dd4a974..9009f312bb 100644
|
|
|
+--- a/modules/stream_out/transcode/transcode.c
|
|
|
++++ b/modules/stream_out/transcode/transcode.c
|
|
|
+@@ -153,6 +153,9 @@ vlc_module_begin ()
|
|
|
+ set_section( N_("Video"), NULL )
|
|
|
+ add_module( SOUT_CFG_PREFIX "venc", "encoder", NULL, VENC_TEXT,
|
|
|
+ VENC_LONGTEXT, false )
|
|
|
++ /* XXX: VERY HACKY */
|
|
|
++ add_string( SOUT_CFG_PREFIX "module", NULL,
|
|
|
++ "define the venc module in venc{} parameters", "", true )
|
|
|
+ add_string( SOUT_CFG_PREFIX "vcodec", NULL, VCODEC_TEXT,
|
|
|
+ VCODEC_LONGTEXT, false )
|
|
|
+ add_integer( SOUT_CFG_PREFIX "vb", 0, VB_TEXT,
|
|
|
+@@ -219,7 +222,7 @@ vlc_module_begin ()
|
|
|
+ vlc_module_end ()
|
|
|
+
|
|
|
+ static const char *const ppsz_sout_options[] = {
|
|
|
+- "venc", "vcodec", "vb",
|
|
|
++ "vcodec", "vb",
|
|
|
+ "scale", "fps", "width", "height", "vfilter", "deinterlace",
|
|
|
+ "deinterlace-module", "threads", "aenc", "acodec", "ab", "alang",
|
|
|
+ "afilter", "samplerate", "channels", "senc", "scodec", "soverlay",
|
|
|
+@@ -227,6 +230,10 @@ static const char *const ppsz_sout_options[] = {
|
|
|
+ NULL
|
|
|
+ };
|
|
|
+
|
|
|
++static const char *const ppsz_venc_options[] = {
|
|
|
++ "vcodec", "module", NULL
|
|
|
++};
|
|
|
++
|
|
|
+ /*****************************************************************************
|
|
|
+ * Exported prototypes
|
|
|
+ *****************************************************************************/
|
|
|
+@@ -241,6 +248,7 @@ static int Open( vlc_object_t *p_this )
|
|
|
+ {
|
|
|
+ sout_stream_t *p_stream = (sout_stream_t*)p_this;
|
|
|
+ sout_stream_sys_t *p_sys;
|
|
|
++ config_chain_t *p_cfg;
|
|
|
+ char *psz_string;
|
|
|
+
|
|
|
+ if( !p_stream->p_next )
|
|
|
+@@ -251,8 +259,17 @@ static int Open( vlc_object_t *p_this )
|
|
|
+ p_sys = calloc( 1, sizeof( *p_sys ) );
|
|
|
+ p_sys->i_master_drift = 0;
|
|
|
+
|
|
|
++ ARRAY_INIT( p_sys->pp_vencs );
|
|
|
++
|
|
|
++ for( p_cfg = p_stream->p_cfg; p_cfg; p_cfg = p_cfg->p_next )
|
|
|
++ {
|
|
|
++ if( !strcmp( p_cfg->psz_name, "venc" ) )
|
|
|
++ ARRAY_APPEND(p_sys->pp_vencs, p_cfg);
|
|
|
++ }
|
|
|
++
|
|
|
++ /* Parse the other option (except venc) */
|
|
|
+ config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
|
|
|
+- p_stream->p_cfg );
|
|
|
++ p_stream->p_cfg );
|
|
|
+
|
|
|
+ /* Audio transcoding parameters */
|
|
|
+ psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "aenc" );
|
|
|
+@@ -310,29 +327,6 @@ static int Open( vlc_object_t *p_this )
|
|
|
+ free( psz_string );
|
|
|
+
|
|
|
+ /* Video transcoding parameters */
|
|
|
+- psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "venc" );
|
|
|
+- p_sys->psz_venc = NULL;
|
|
|
+- p_sys->p_video_cfg = NULL;
|
|
|
+- if( psz_string && *psz_string )
|
|
|
+- {
|
|
|
+- char *psz_next;
|
|
|
+- psz_next = config_ChainCreate( &p_sys->psz_venc, &p_sys->p_video_cfg,
|
|
|
+- psz_string );
|
|
|
+- free( psz_next );
|
|
|
+- }
|
|
|
+- free( psz_string );
|
|
|
+-
|
|
|
+- psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "vcodec" );
|
|
|
+- p_sys->i_vcodec = 0;
|
|
|
+- if( psz_string && *psz_string )
|
|
|
+- {
|
|
|
+- char fcc[5] = " \0";
|
|
|
+- memcpy( fcc, psz_string, __MIN( strlen( psz_string ), 4 ) );
|
|
|
+- p_sys->i_vcodec = vlc_fourcc_GetCodecFromString( VIDEO_ES, fcc );
|
|
|
+- msg_Dbg( p_stream, "Checking video codec mapping for %s got %4.4s ", fcc, (char*)&p_sys->i_vcodec);
|
|
|
+- }
|
|
|
+- free( psz_string );
|
|
|
+-
|
|
|
+ p_sys->i_vbitrate = var_GetInteger( p_stream, SOUT_CFG_PREFIX "vb" );
|
|
|
+ if( p_sys->i_vbitrate < 16000 ) p_sys->i_vbitrate *= 1000;
|
|
|
+
|
|
|
+@@ -435,6 +429,11 @@ static void Close( vlc_object_t * p_this )
|
|
|
+ sout_stream_t *p_stream = (sout_stream_t*)p_this;
|
|
|
+ sout_stream_sys_t *p_sys = p_stream->p_sys;
|
|
|
+
|
|
|
++ if( p_sys->p_venc_conf )
|
|
|
++ vlc_object_release( p_sys->p_venc_conf );
|
|
|
++
|
|
|
++ ARRAY_RESET(p_sys->pp_vencs);
|
|
|
++
|
|
|
+ free( p_sys->psz_af );
|
|
|
+
|
|
|
+ config_ChainDestroy( p_sys->p_audio_cfg );
|
|
|
+@@ -481,6 +480,30 @@ static void DeleteSoutStreamID( sout_stream_id_sys_t *id )
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
++static encoder_t *InitEncoder( vlc_object_t *p_parent,
|
|
|
++ sout_stream_t *p_stream,
|
|
|
++ const es_format_t *p_fmt )
|
|
|
++{
|
|
|
++ sout_stream_sys_t *p_sys = p_stream->p_sys;
|
|
|
++ encoder_t *p_encoder = sout_EncoderCreate( p_parent );
|
|
|
++ if( !p_encoder )
|
|
|
++ return NULL;
|
|
|
++ p_encoder->p_module = NULL;
|
|
|
++
|
|
|
++ /* Create destination format */
|
|
|
++ es_format_Init( &p_encoder->fmt_in, p_fmt->i_cat, 0 );
|
|
|
++ es_format_Init( &p_encoder->fmt_out, p_fmt->i_cat, 0 );
|
|
|
++ p_encoder->fmt_out.i_id = p_fmt->i_id;
|
|
|
++ p_encoder->fmt_out.i_group = p_fmt->i_group;
|
|
|
++
|
|
|
++ if( p_sys->psz_alang )
|
|
|
++ p_encoder->fmt_out.psz_language = strdup( p_sys->psz_alang );
|
|
|
++ else if( p_fmt->psz_language )
|
|
|
++ p_encoder->fmt_out.psz_language = strdup( p_fmt->psz_language );
|
|
|
++
|
|
|
++ return p_encoder;
|
|
|
++}
|
|
|
++
|
|
|
+ static sout_stream_id_sys_t *Add( sout_stream_t *p_stream,
|
|
|
+ const es_format_t *p_fmt )
|
|
|
+ {
|
|
|
+@@ -499,49 +522,173 @@ static sout_stream_id_sys_t *Add( sout_stream_t *p_stream,
|
|
|
+ /* Create decoder object */
|
|
|
+ id->p_decoder = vlc_object_create( p_stream, sizeof( decoder_t ) );
|
|
|
+ if( !id->p_decoder )
|
|
|
++ {
|
|
|
++ msg_Err( p_stream, "cannot create decoder" );
|
|
|
+ goto error;
|
|
|
++ }
|
|
|
+ id->p_decoder->p_module = NULL;
|
|
|
+ es_format_Init( &id->p_decoder->fmt_out, p_fmt->i_cat, 0 );
|
|
|
+ es_format_Copy( &id->p_decoder->fmt_in, p_fmt );
|
|
|
+ id->p_decoder->b_frame_drop_allowed = false;
|
|
|
+
|
|
|
+ /* Create encoder object */
|
|
|
+- id->p_encoder = sout_EncoderCreate( p_stream );
|
|
|
+- if( !id->p_encoder )
|
|
|
+- goto error;
|
|
|
+- id->p_encoder->p_module = NULL;
|
|
|
+-
|
|
|
+- /* Create destination format */
|
|
|
+- es_format_Init( &id->p_encoder->fmt_in, p_fmt->i_cat, 0 );
|
|
|
+- es_format_Init( &id->p_encoder->fmt_out, p_fmt->i_cat, 0 );
|
|
|
+- id->p_encoder->fmt_out.i_id = p_fmt->i_id;
|
|
|
+- id->p_encoder->fmt_out.i_group = p_fmt->i_group;
|
|
|
++ if( p_fmt->i_cat == VIDEO_ES ) //&& p_sys->i_vcodec )
|
|
|
++ {
|
|
|
++ for( int config_idx=0;
|
|
|
++ config_idx<p_sys->pp_vencs.i_size;
|
|
|
++ config_idx++ )
|
|
|
++ {
|
|
|
++ config_chain_t *p_enc_cfg = ARRAY_VAL( p_sys->pp_vencs, config_idx );
|
|
|
++
|
|
|
++ /* the encoder config will be hold by the encoder if it succeed */
|
|
|
++ p_sys->p_venc_conf =
|
|
|
++ vlc_object_create( p_stream, sizeof(vlc_object_t) );
|
|
|
++
|
|
|
++ msg_Dbg( p_stream, "trying configuration venc={%s}",
|
|
|
++ p_enc_cfg->psz_value );
|
|
|
++
|
|
|
++ size_t length = strlen( p_enc_cfg->psz_value );
|
|
|
++ size_t first_equal = strcspn( p_enc_cfg->psz_value, "=" );
|
|
|
++ size_t first_brace = strcspn( p_enc_cfg->psz_value, "{" );
|
|
|
++ size_t first_comma = strcspn( p_enc_cfg->psz_value, "," );
|
|
|
++
|
|
|
++ config_ChainDestroy( p_sys->p_video_cfg );
|
|
|
++ free( p_sys->psz_venc );
|
|
|
++
|
|
|
++ p_sys->psz_venc = NULL;
|
|
|
++ p_sys->p_video_cfg = NULL;
|
|
|
++
|
|
|
++ if( first_comma == length
|
|
|
++ && first_equal > first_brace )
|
|
|
++ {
|
|
|
++ /* venc configuration is in the legacy form */
|
|
|
++ char *psz_next;
|
|
|
++ psz_next = config_ChainCreate( &p_sys->psz_venc,
|
|
|
++ &p_sys->p_video_cfg,
|
|
|
++ p_enc_cfg->psz_value );
|
|
|
++ free( psz_next );
|
|
|
++ }
|
|
|
++ else
|
|
|
++ {
|
|
|
++ /* venc configuration is in the new extended form */
|
|
|
++ config_chain_t *p_conf;
|
|
|
++ config_ChainParseOptions( &p_conf, p_enc_cfg->psz_value );
|
|
|
++ config_ChainParse( p_sys->p_venc_conf, SOUT_CFG_PREFIX,
|
|
|
++ ppsz_venc_options, p_conf );
|
|
|
++ config_ChainDestroy( p_conf );
|
|
|
++
|
|
|
++ p_sys->psz_venc = NULL;
|
|
|
++ p_sys->p_video_cfg = NULL;
|
|
|
++ char *psz_string = var_GetString( p_sys->p_venc_conf,
|
|
|
++ SOUT_CFG_PREFIX "module" );
|
|
|
++
|
|
|
++
|
|
|
++ if( !psz_string )
|
|
|
++ {
|
|
|
++ msg_Err( p_stream,
|
|
|
++ "missing key \"encoder\" in extended venc option: %s",
|
|
|
++ p_enc_cfg->psz_value );
|
|
|
++ vlc_object_release( p_sys->p_venc_conf );
|
|
|
++ p_sys->p_venc_conf = NULL;
|
|
|
++ continue;
|
|
|
++ }
|
|
|
++
|
|
|
++
|
|
|
++ char *psz_next;
|
|
|
++ psz_next = config_ChainCreate( &p_sys->psz_venc,
|
|
|
++ &p_sys->p_video_cfg,
|
|
|
++ psz_string );
|
|
|
++ free( psz_next );
|
|
|
++ free( psz_string );
|
|
|
++ }
|
|
|
++
|
|
|
++ char *psz_vcodec = var_GetString( p_sys->p_venc_conf,
|
|
|
++ SOUT_CFG_PREFIX "vcodec" );
|
|
|
++ if( psz_vcodec == NULL )
|
|
|
++ psz_vcodec = var_InheritString( p_sys->p_venc_conf,
|
|
|
++ SOUT_CFG_PREFIX "vcodec" );
|
|
|
++ p_sys->i_vcodec = 0;
|
|
|
++ if( psz_vcodec && *psz_vcodec )
|
|
|
++ {
|
|
|
++ char fcc[5] = " \0";
|
|
|
++ memcpy( fcc, psz_vcodec, __MIN( strlen( psz_vcodec ), 4 ) );
|
|
|
++ p_sys->i_vcodec = vlc_fourcc_GetCodecFromString( VIDEO_ES, fcc );
|
|
|
++ msg_Dbg( p_stream, "Checking video codec mapping for %s got %4.4s ", fcc, (char*)&p_sys->i_vcodec);
|
|
|
++ }
|
|
|
++ free( psz_vcodec );
|
|
|
++
|
|
|
++
|
|
|
++ id->p_encoder = InitEncoder( p_sys->p_venc_conf, p_stream, p_fmt );
|
|
|
++ if( !id->p_encoder )
|
|
|
++ {
|
|
|
++ msg_Warn( p_stream, "cannot initialize encoder" );
|
|
|
++ vlc_object_release( p_sys->p_venc_conf );
|
|
|
++ p_sys->p_venc_conf = NULL;
|
|
|
++ continue;
|
|
|
++ }
|
|
|
++
|
|
|
++ if( !p_sys->i_vcodec )
|
|
|
++ {
|
|
|
++ msg_Warn( p_stream,
|
|
|
++ "cannot use config venc={%s}, no vcodec defined",
|
|
|
++ p_enc_cfg->psz_value );
|
|
|
++
|
|
|
++ es_format_Clean( &id->p_encoder->fmt_out );
|
|
|
++ vlc_object_release( p_sys->p_venc_conf );
|
|
|
++ p_sys->p_venc_conf = NULL;
|
|
|
++
|
|
|
++ vlc_object_release( id->p_encoder );
|
|
|
++ id->p_encoder = NULL;
|
|
|
++ continue;
|
|
|
++ }
|
|
|
++
|
|
|
++ if( !transcode_video_add( p_stream, p_fmt, id ) )
|
|
|
++ {
|
|
|
++ msg_Warn( p_stream,
|
|
|
++ "can't use transcode configuration with venc=%s",
|
|
|
++ p_enc_cfg->psz_value );
|
|
|
++ es_format_Clean( &id->p_encoder->fmt_out );
|
|
|
++
|
|
|
++ vlc_object_release( p_sys->p_venc_conf );
|
|
|
++ p_sys->p_venc_conf = NULL;
|
|
|
++
|
|
|
++ vlc_object_release( id->p_encoder );
|
|
|
++ id->p_encoder = NULL;
|
|
|
++ continue;
|
|
|
++ }
|
|
|
++
|
|
|
++ msg_Info( p_stream, "using venc={%s} configuration for transcoding",
|
|
|
++ p_enc_cfg->psz_value );
|
|
|
++ break;
|
|
|
++ }
|
|
|
++ }
|
|
|
++ else
|
|
|
++ {
|
|
|
++ id->p_encoder = InitEncoder( VLC_OBJECT(p_stream), p_stream, p_fmt );
|
|
|
+
|
|
|
+- if( p_sys->psz_alang )
|
|
|
+- id->p_encoder->fmt_out.psz_language = strdup( p_sys->psz_alang );
|
|
|
+- else if( p_fmt->psz_language )
|
|
|
+- id->p_encoder->fmt_out.psz_language = strdup( p_fmt->psz_language );
|
|
|
++ bool success;
|
|
|
+
|
|
|
+- bool success;
|
|
|
++ if( p_fmt->i_cat == AUDIO_ES && p_sys->i_acodec )
|
|
|
++ success = transcode_audio_add(p_stream, p_fmt, id);
|
|
|
++ else if( ( p_fmt->i_cat == SPU_ES ) &&
|
|
|
++ ( p_sys->i_scodec || p_sys->b_soverlay ) )
|
|
|
++ success = transcode_spu_add(p_stream, p_fmt, id);
|
|
|
++ else
|
|
|
++ {
|
|
|
++ msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')",
|
|
|
++ (char*)&p_fmt->i_codec );
|
|
|
++ id->id = sout_StreamIdAdd( p_stream->p_next, p_fmt );
|
|
|
++ id->b_transcode = false;
|
|
|
+
|
|
|
+- if( p_fmt->i_cat == AUDIO_ES && p_sys->i_acodec )
|
|
|
+- success = transcode_audio_add(p_stream, p_fmt, id);
|
|
|
+- else if( p_fmt->i_cat == VIDEO_ES && p_sys->i_vcodec )
|
|
|
+- success = transcode_video_add(p_stream, p_fmt, id);
|
|
|
+- else if( ( p_fmt->i_cat == SPU_ES ) &&
|
|
|
+- ( p_sys->i_scodec || p_sys->b_soverlay ) )
|
|
|
+- success = transcode_spu_add(p_stream, p_fmt, id);
|
|
|
+- else
|
|
|
+- {
|
|
|
+- msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')",
|
|
|
+- (char*)&p_fmt->i_codec );
|
|
|
+- id->id = sout_StreamIdAdd( p_stream->p_next, p_fmt );
|
|
|
+- id->b_transcode = false;
|
|
|
++ success = id->id;
|
|
|
++ }
|
|
|
+
|
|
|
+- success = id->id;
|
|
|
++ if (!success)
|
|
|
++ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+- if(!success)
|
|
|
++
|
|
|
++ if( !id->p_encoder )
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ return id;
|
|
|
+diff --git a/modules/stream_out/transcode/transcode.h b/modules/stream_out/transcode/transcode.h
|
|
|
+index 1b5e886d94..e2ba426030 100644
|
|
|
+--- a/modules/stream_out/transcode/transcode.h
|
|
|
++++ b/modules/stream_out/transcode/transcode.h
|
|
|
+@@ -38,6 +38,8 @@ struct sout_stream_sys_t
|
|
|
+ char *psz_af;
|
|
|
+
|
|
|
+ /* Video */
|
|
|
++ DECL_ARRAY(config_chain_t *) pp_vencs;
|
|
|
++ vlc_object_t *p_venc_conf;
|
|
|
+ vlc_fourcc_t i_vcodec; /* codec video (0 if not transcode) */
|
|
|
+ char *psz_venc;
|
|
|
+ config_chain_t *p_video_cfg;
|
|
|
+--
|
|
|
+2.17.1
|
|
|
+
|