Commit 553a5da7 authored by Alexandre Janniaux's avatar Alexandre Janniaux Committed by Carola Nitz

libvlc: Add multiple venc support in transcode

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.

(cherry picked from commit 90e06eb1)
parent fc328c5c
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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment