Commit 354bc77a authored by Antoine Cellerier's avatar Antoine Cellerier Committed by Jean-Paul Saman

Add a bunch of options to the davinci codec to make it possible to override...

Add a bunch of options to the davinci codec to make it possible to override default engine and codec name without having to rebuild VLC. Also make it possible to chose the video decoder output chroma on the command line.
Signed-off-by: Jean-Paul Saman's avatarJean-Paul Saman <jean-paul.saman@m2x.nl>
parent e73a6ebc
......@@ -50,26 +50,49 @@ struct decoder_sys_t
*****************************************************************************/
int OpenAudioDecoder( vlc_object_t *p_this )
{
#if 0
decoder_t *p_dec = (decoder_t *)p_this;
decoder_sys_t *p_sys;
Engine_Error err;
const char *psz_codec;
char *psz_codec = NULL;
char *psz_engine = NULL;
AUDDEC_Params params;
psz_codec = config_GetPsz( p_this, "davinci-auddec-codec" );
if( psz_codec && !*psz_codec )
{
free( psz_codec );
psz_codec = NULL;
}
if( psz_codec )
{
char *psz_fourcc = config_GetPsz( p_this, "davinci-auddec-fourcc" );
if( strlen( psz_fourcc ) != 4 || p_dec->fmt_in.i_codec !=
VLC_FOURCC(psz_fourcc[0],psz_fourcc[1],psz_fourcc[2],psz_fourcc[3]))
{
free( psz_codec );
free( psz_fourcc );
return VLC_EGENERIC;
}
free( psz_fourcc );
msg_Dbg( p_this, "Forcing use of audio decoder `%s'", psz_codec );
}
else
{
switch( p_dec->fmt_in.i_codec )
{
CASE_MP3
psz_codec = "mp3dec";
psz_codec = strdup( "mp3dec" );
break;
CASE_AAC
psz_codec = "aacdec";
psz_codec = strdup( "aacdec" );
break;
default:
return VLC_EGENERIC;
}
}
/* Allocate our private structure */
p_dec->p_sys = (decoder_sys_t *)malloc( sizeof( decoder_sys_t ) );
......@@ -82,14 +105,16 @@ int OpenAudioDecoder( vlc_object_t *p_this )
CERuntime_init();
/* Create an engine handle */
p_sys->e = Engine_open( "decode", NULL /*&Engine_ATTRS*/, &err );
psz_engine = config_GetPsz( p_dec, "davinci-auddec-engine" );
p_sys->e = Engine_open( psz_engine, NULL /*&Engine_ATTRS*/, &err );
if( err != Engine_EOK )
{
msg_Err( p_dec, ppsz_engine_error[err] );
msg_Err( p_dec, "Error while opening engine `%s': %s",
psz_engine, ppsz_engine_error[err] );
goto error;
}
PrintAvailableAlgorithms( p_this, "decode" );
PrintAvailableAlgorithms( p_this, psz_engine );
/* Create audio decoder */
params.size = sizeof( params );
......@@ -114,12 +139,15 @@ int OpenAudioDecoder( vlc_object_t *p_this )
msg_Info( p_dec, "Wooooohooo!" );
#endif
free( psz_codec );
free( psz_engine );
return VLC_SUCCESS;
error:
if( p_sys->e ) Engine_close( p_sys->e );
free( p_sys );
#endif
free( psz_codec );
free( psz_engine );
return VLC_EGENERIC;
}
......@@ -162,7 +190,7 @@ static aout_buffer_t *DecodeAudioBlock( decoder_t *p_dec, block_t **pp_block )
AUDDEC_Status status;
int i;
if( !pp_block || !*pp_block ) return NULL;
if( !pp_block || !*pp_block ) return NULL;
p_block = *pp_block;
#ifdef DEBUG_DAVINCI
......
......@@ -29,27 +29,86 @@
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#define VIDDEC_ENGINE_TEXT N_( "Video decoder engine" )
#define VIDDEC_ENGINE_LONGTEXT N_( \
"Name of the decoder engine used to decode video" )
#define VIDDEC_CODEC_TEXT N_( "Video decoder name" )
#define VIDDEC_CODEC_LONGTEXT N_( \
"Force usage of a specific video decoder in engine. " \
"Leave empty to autodetect." )
#define VIDDEC_FOURCC_TEXT N_( "Match against FOURCC" )
#define VIDDEC_FOURCC_LONGTEXT N_( \
"Use davinci video decoder module for this FOURCC. Option should be " \
"set when viddec-codec is used." )
#define VIDDEC_CHROMA_TEXT N_( "Decoder output chroma" )
#define VIDDEC_CHROMA_LONGTEXT N_( \
"Force video decoder to output in specific chroma" )
#define AUDDEC_ENGINE_TEXT N_( "Audio decoder engine" )
#define AUDDEC_ENGINE_LONGTEXT N_( \
"Name of the decoder engine used to decode audio" )
#define AUDDEC_CODEC_TEXT N_( "Audio decoder name" )
#define AUDDEC_CODEC_LONGTEXT N_( \
"Force usage of a specific audio decoder in engine. " \
"Leave empty to autodetect." )
#define AUDDEC_FOURCC_TEXT N_( "Match against FOURCC" )
#define AUDDEC_FOURCC_LONGTEXT N_( \
"Use davinci audio decoder module for this FOURCC. Option should be " \
"set when auddec-codec is used." )
#define VIDENC_ENGINE_TEXT N_( "Video encoder engine" )
#define VIDENC_ENGINE_LONGTEXT N_( \
"Name of the encoder engine used to encode video" )
#define VIDENC_CODEC_TEXT N_( "Video encoder name" )
#define VIDENC_CODEC_LONGTEXT N_( \
"Force usage of a specific video encoder in engine. " \
"Leave empty to autodetect." )
#define VIDENC_FOURCC_TEXT N_( "Match against FOURCC" )
#define VIDENC_FOURCC_LONGTEXT N_( \
"Use davinci video encoder module for this FOURCC. Option should be " \
"set when videnc-codec is used." )
vlc_module_begin();
set_category( CAT_INPUT );
set_subcategory( SUBCAT_INPUT_VCODEC );
set_description( _("DaVinci DSP video decoder") );
set_capability( "decoder", 1337 );
set_callbacks( OpenVideoDecoder, CloseVideoDecoder );
add_string( "davinci-viddec-engine", "decode", NULL,
VIDDEC_ENGINE_TEXT, VIDDEC_ENGINE_LONGTEXT, VLC_TRUE );
add_string( "davinci-viddec-codec", "", NULL,
VIDDEC_CODEC_TEXT, VIDDEC_CODEC_LONGTEXT, VLC_TRUE );
add_string( "davinci-viddec-fourcc", "", NULL,
VIDDEC_FOURCC_TEXT, VIDDEC_FOURCC_LONGTEXT, VLC_TRUE );
add_string( "davinci-viddec-chroma", "", NULL,
VIDDEC_CHROMA_TEXT, VIDDEC_CHROMA_LONGTEXT, VLC_TRUE );
add_submodule();
set_description( _("DaVinci DSP audio decoder") );
set_capability( "decoder", 1337 );
set_callbacks( OpenAudioDecoder, CloseAudioDecoder );
add_string( "davinci-auddec-engine", "decode", NULL,
AUDDEC_ENGINE_TEXT, AUDDEC_ENGINE_LONGTEXT, VLC_TRUE );
add_string( "davinci-auddec-codec", "", NULL,
AUDDEC_CODEC_TEXT, AUDDEC_CODEC_LONGTEXT, VLC_TRUE );
add_string( "davinci-auddec-fourcc", "", NULL,
AUDDEC_FOURCC_TEXT, AUDDEC_FOURCC_LONGTEXT, VLC_TRUE );
add_submodule();
set_description( _("DaVinci DSP video encoder" ) );
set_capability( "encoder", 1337 );
set_callbacks( OpenVideoEncoder, CloseVideoEncoder );
add_string( "davinci-videnc-engine", "encode", NULL,
VIDENC_ENGINE_TEXT, VIDENC_ENGINE_LONGTEXT, VLC_TRUE );
add_string( "davinci-videnc-codec", "", NULL,
VIDENC_CODEC_TEXT, VIDENC_CODEC_LONGTEXT, VLC_TRUE );
add_string( "davinci-videnc-fourcc", "", NULL,
VIDENC_FOURCC_TEXT, VIDENC_FOURCC_LONGTEXT, VLC_TRUE );
vlc_module_end();
/*****************************************************************************
* Misc utils
* Memory utils
*****************************************************************************/
#include <ti/sdo/ce/osal/Memory.h>
......@@ -116,6 +175,28 @@ void FreeBuffer( XDM_BufDesc *buf )
}
}
/*****************************************************************************
* Misc utils
*****************************************************************************/
const char *ppsz_engine_error[] = {
[Engine_EOK] = "Ok",
[Engine_EEXIST] = "Engine name doesn't exist",
[Engine_ENOMEM] = "Can't allocate engine memory",
[Engine_EDSPLOAD] = "Can't load the DSP",
[Engine_ENOCOMM] = "Can't create communication connection to DSP",
[Engine_ENOSERVER] = "Can't locate the server on the DSP",
[Engine_ECOMALLOC] = "Can't allocate communication buffer",
[Engine_ERUNTIME] = "Engine runtime failure",
[Engine_ECODECCREATE] = "Engine codec creation failed",
[Engine_ECODECSTART] = "Engine codec start failed",
[Engine_EINVAL] = "Bad parameter",
[Engine_EBADSERVER] = "Incompatible server specified",
[Engine_ENOTAVAIL] = "Service not available",
//[Engine_EWRONGSTATE] = "Call can't be made at this time",
//[Engine_EINUSE] = "Call can't be made at this time because a required resource is in use",
//[Engine_ENOTFOUND] = "Entity was not found",
};
void __PrintExtendedError( vlc_object_t *p_this, XDAS_Int32 error )
{
if( XDM_ISAPPLIEDCONCEALMENT( error ) )
......@@ -142,7 +223,7 @@ void __PrintAvailableAlgorithms( vlc_object_t *p_this, const char *psz_engine )
msg_Dbg( p_this, "Available algorithms in engine `%s':", psz_engine );
while( Engine_getAlgInfo( (String)psz_engine, &info, i ) == Engine_EOK )
{
const char **psz_type = info.typeTab;
const char **psz_type = (const char **)info.typeTab;
i++;
msg_Dbg( p_this, " %d: %s (%s)", i, info.name, info.isLocal?"local":"remote" );
if( *psz_type )
......@@ -153,3 +234,40 @@ void __PrintAvailableAlgorithms( vlc_object_t *p_this, const char *psz_engine )
}
}
}
XDAS_Int32 VlcChromaToXdm( vlc_fourcc_t i_chroma )
{
switch( i_chroma )
{
case VLC_FOURCC('I','4','2','0'):
return XDM_YUV_420P;
case VLC_FOURCC('I','4','1','1'):
return XDM_YUV_411P;
case VLC_FOURCC('I','4','2','2'):
return XDM_YUV_422P;
case VLC_FOURCC('I','4','4','4'):
return XDM_YUV_444P;
case VLC_FOURCC('Y','U','Y','V'):
return XDM_YUV_422IBE; /* FIXME ? */
case VLC_FOURCC('U','Y','V','Y'):
return XDM_YUV_422ILE; /* FIXME ? */
case VLC_FOURCC('G','R','E','Y'):
return XDM_GRAY;
#if 0
/* FIXME: not sure about this one */
case VLC_FOURCC('R','V','2','4'):
case VLC_FOURCC('R','V','3','2'):
return XDM_RGB;
#endif
default:
return 0;
}
}
......@@ -52,28 +52,12 @@ void __PrintExtendedError( vlc_object_t *, XDAS_Int32 );
#define PrintExtendedError( a, b ) __PrintExtendedError( VLC_OBJECT( a ), b )
void __PrintAvailableAlgorithms( vlc_object_t *, const char * );
#define PrintAvailableAlgorithms( a, b ) __PrintAvailableAlgorithms( VLC_OBJECT( a ), b )
XDAS_Int32 VlcChromaToXdm( vlc_fourcc_t );
/*****************************************************************************
* Common stuff
*****************************************************************************/
static const char *ppsz_engine_error[] = {
[Engine_EOK] = "Ok",
[Engine_EEXIST] = "Engine name doesn't exist",
[Engine_ENOMEM] = "Can't allocate engine memory",
[Engine_EDSPLOAD] = "Can't load the DSP",
[Engine_ENOCOMM] = "Can't create communication connection to DSP",
[Engine_ENOSERVER] = "Can't locate the server on the DSP",
[Engine_ECOMALLOC] = "Can't allocate communication buffer",
[Engine_ERUNTIME] = "Engine runtime failure",
[Engine_ECODECCREATE] = "Engine codec creation failed",
[Engine_ECODECSTART] = "Engine codec start failed",
[Engine_EINVAL] = "Bad parameter",
[Engine_EBADSERVER] = "Incompatible server specified",
[Engine_ENOTAVAIL] = "Service not available",
//[Engine_EWRONGSTATE] = "Call can't be made at this time",
//[Engine_EINUSE] = "Call can't be made at this time because a required resource is in use",
//[Engine_ENOTFOUND] = "Entity was not found",
};
extern const char *ppsz_engine_error[];
/* FOURCC codes copied from libavcodec module */
#define CASE_MPEG1 \
......
......@@ -53,38 +53,64 @@ int OpenVideoDecoder( vlc_object_t *p_this )
decoder_t *p_dec = (decoder_t*)p_this;
decoder_sys_t *p_sys;
Engine_Error err;
const char *psz_codec;
char *psz_codec = NULL;
char *psz_engine = NULL;
char *psz_chroma = NULL;
vlc_fourcc_t i_chroma = VLC_FOURCC('I','4','2','0'); /* VLC_FOURCC('U','Y','V','Y') */
VIDDEC_Params params;
psz_codec = config_GetPsz( p_this, "davinci-viddec-codec" );
if( psz_codec && !*psz_codec )
{
free( psz_codec );
psz_codec = NULL;
}
if( psz_codec )
{
char *psz_fourcc = config_GetPsz( p_this, "davinci-viddec-fourcc" );
if( strlen( psz_fourcc ) != 4 || p_dec->fmt_in.i_codec !=
VLC_FOURCC(psz_fourcc[0],psz_fourcc[1],psz_fourcc[2],psz_fourcc[3]))
{
free( psz_codec );
free( psz_fourcc );
return VLC_EGENERIC;
}
free( psz_fourcc );
msg_Dbg( p_this, "Forcing use of video decoder `%s'", psz_codec );
}
else
{
switch( p_dec->fmt_in.i_codec )
{
#if 0
CASE_MPEG1
psz_codec = "mpegdec"; /* FIXME */
psz_codec = strdup( "mpegdec" ); /* FIXME */
break;
#endif
CASE_MPEG2
psz_codec = "mpeg2dec";
psz_codec = strdup( "mpeg2dec" );
break;
CASE_MPEG4
psz_codec = "mpeg4dec";
psz_codec = strdup( "mpeg4dec" );
break;
CASE_H264
psz_codec = "h264dec";
psz_codec = strdup( "h264dec" );
break;
#if 0
CASE_VC1
psz_codec = "vc1dec"; /* FIXME */
psz_codec = strdup( "vc1dec" ); /* FIXME */
break;
#endif
default:
return VLC_EGENERIC;
}
}
/* Allocate our private structure */
p_dec->p_sys = (decoder_sys_t *)malloc( sizeof( decoder_sys_t ) );
......@@ -97,14 +123,26 @@ int OpenVideoDecoder( vlc_object_t *p_this )
CERuntime_init();
/* Create an engine handle */
p_sys->e = Engine_open( "decode", NULL /*&Engine_ATTRS*/, &err );
psz_engine = config_GetPsz( p_dec, "davinci-viddec-engine" );
p_sys->e = Engine_open( psz_engine, NULL /*&Engine_ATTRS*/, &err );
if( err != Engine_EOK )
{
msg_Err( p_dec, ppsz_engine_error[err] );
msg_Err( p_dec, "Error while opening engine `%s': %s",
psz_engine, ppsz_engine_error[err] );
goto error;
}
PrintAvailableAlgorithms( p_this, "decode" );
PrintAvailableAlgorithms( p_this, psz_engine );
/* Get user supplied chroma setting */
psz_chroma = config_GetPsz( p_dec, "davinci-viddec-chroma" );
if( psz_chroma && strlen( psz_chroma ) == 4 )
{
i_chroma = VLC_FOURCC( psz_chroma[0], psz_chroma[1],
psz_chroma[2], psz_chroma[3] );
msg_Dbg( p_dec, "Forcing output chroma to `%s'", psz_chroma );
}
free( psz_chroma );
/* Create video decoder */
params.size = sizeof( VIDDEC_Params );
......@@ -113,8 +151,7 @@ int OpenVideoDecoder( vlc_object_t *p_this )
params.maxFrameRate = 0; /* in frames per 1000 seconds */
params.maxBitRate = 0; /* in bits per second */
params.dataEndianness = XDM_BYTE;//LE_32;
params.forceChromaFormat = XDM_YUV_420P;
//params.forceChromaFormat = XDM_YUV_422ILE;
params.forceChromaFormat = VlcChromaToXdm( i_chroma );
/* Or do we want to output directly to XDM_YUV_422ILE as that's what the
* frame buffer likes? */
......@@ -133,8 +170,8 @@ int OpenVideoDecoder( vlc_object_t *p_this )
msg_Info( p_dec, "fmt_out.video.i_height: %d", p_dec->fmt_out.video.i_height );
#endif
p_dec->fmt_out.i_cat = VIDEO_ES;
p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','0');
//p_dec->fmt_out.i_codec = VLC_FOURCC('U','Y','V','Y');
p_dec->fmt_out.i_codec =
p_dec->fmt_out.video.i_chroma = i_chroma;
p_dec->fmt_out.video.i_width = p_dec->fmt_in.video.i_width;
p_dec->fmt_out.video.i_height = p_dec->fmt_in.video.i_height;
p_dec->fmt_out.video.i_aspect = p_dec->fmt_in.video.i_aspect;
......@@ -146,11 +183,15 @@ int OpenVideoDecoder( vlc_object_t *p_this )
msg_Info( p_dec, "Woohoo!" );
#endif
free( psz_codec );
free( psz_engine );
return VLC_SUCCESS;
error:
if( p_sys->e ) Engine_close( p_sys->e );
free( p_sys );
free( psz_codec );
free( psz_engine );
return VLC_EGENERIC;
}
......@@ -253,7 +294,7 @@ static picture_t *DecodeVideoBlock( decoder_t *p_dec, block_t **pp_block )
msg_Dbg( p_dec, "Woah! Not enough room to store the whole block" );
#endif
memcpy( p_sys->in.bufs[0], p_block->p_buffer, in_args.numBytes );
msg_Warn( p_dec, "Sending %d bytes", in_args.numBytes );
msg_Warn( p_dec, "Sending %d bytes", (int)in_args.numBytes );
#if 0
/* This obviously doesn't work (at least for mpeg2 video */
......@@ -352,8 +393,6 @@ static picture_t *DecodeVideoBlock( decoder_t *p_dec, block_t **pp_block )
p_dec->fmt_out.video.i_width = status.outputWidth;
p_dec->fmt_out.video.i_height = status.outputHeight;
p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR * status.outputWidth / status.outputHeight; /* FIXME */
p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','0');
//p_dec->fmt_out.i_codec = VLC_FOURCC('U','Y','V','Y');
/* Get a new picture */
p_pic = p_dec->pf_vout_buffer_new( p_dec );
......
......@@ -53,39 +53,63 @@ int OpenVideoEncoder( vlc_object_t *p_this )
{
encoder_t *p_enc = (encoder_t *)p_this;
encoder_sys_t *p_sys;
const char *psz_codec;
char *psz_codec = NULL;
char *psz_engine = NULL;
Engine_Error err;
VIDENC_Params params;
psz_codec = config_GetPsz( p_this, "davinci-videnc-codec" );
if( psz_codec && !*psz_codec )
{
free( psz_codec );
psz_codec = NULL;
}
if( psz_codec )
{
char *psz_fourcc = config_GetPsz( p_this, "davinci-videnc-fourcc" );
if( strlen( psz_fourcc ) != 4 || p_enc->fmt_out.i_codec !=
VLC_FOURCC(psz_fourcc[0],psz_fourcc[1],psz_fourcc[2],psz_fourcc[3]))
{
free( psz_codec );
free( psz_fourcc );
return VLC_EGENERIC;
}
free( psz_fourcc );
msg_Dbg( p_this, "Forcing use of video encoder `%s'", psz_codec );
}
else
{
switch( p_enc->fmt_out.i_codec )
{
#if 0
CASE_MPEG1
psz_codec = "mpegenc"; /* FIXME */
psz_codec = strdup( "mpegenc" ); /* FIXME */
break;
CASE_MPEG2
psz_codec = "mpeg2enc"; /* FIXME */
psz_codec = strdup( "mpeg2enc" ); /* FIXME */
break;
#endif
CASE_MPEG4
psz_codec = "mpeg4enc";
psz_codec = strdup( "mpeg4enc" );
break;
CASE_H264
psz_codec = "h264enc";
psz_codec = strdup( "h264enc" );
break;
#if 0
CASE_VC1
psz_codec = "vc1enc"; /* FIXME */
psz_codec = strdup( "vc1enc" ); /* FIXME */
break;
#endif
default:
return VLC_EGENERIC;
}
}
/* Allocate our private structure */
p_enc->p_sys = (encoder_sys_t *)malloc( sizeof( encoder_sys_t ) );
......@@ -98,14 +122,16 @@ int OpenVideoEncoder( vlc_object_t *p_this )
CERuntime_init();
/* Create an engine handle */
p_sys->e = Engine_open( "encode", NULL /*&Engine_ATTRS*/, &err );
psz_engine = config_GetPsz( p_enc, "davinci-videnc-engine" );
p_sys->e = Engine_open( psz_engine, NULL /*&Engine_ATTRS*/, &err );
if( err != Engine_EOK )
{
msg_Err( p_enc, ppsz_engine_error[err] );
msg_Err( p_enc, "Error while opening engine `%s': %s",
psz_engine, ppsz_engine_error[err] );
goto error;
}
PrintAvailableAlgorithms( p_this, "encode" );
PrintAvailableAlgorithms( p_this, psz_engine );
/* Configure encoder */
params.size = sizeof( params );
......@@ -121,45 +147,9 @@ int OpenVideoEncoder( vlc_object_t *p_this )
+ p_enc->i_tolerance; /* Bits per second. FIXME? */
params.dataEndianness = XDM_BYTE;
params.maxInterFrameInterval = p_enc->i_iframes; /* FIXME? */
switch( p_enc->fmt_in.video.i_chroma )
params.inputChromaFormat = VlcChromaToXdm( p_enc->fmt_in.video.i_chroma );
if( !params.inputChromaFormat )
{
case VLC_FOURCC('I','4','2','0'):
params.inputChromaFormat = XDM_YUV_420P;
break;
case VLC_FOURCC('I','4','1','1'):
params.inputChromaFormat = XDM_YUV_411P;
break;
case VLC_FOURCC('I','4','2','2'):
params.inputChromaFormat = XDM_YUV_422P;
break;
case VLC_FOURCC('I','4','4','4'):
params.inputChromaFormat = XDM_YUV_444P;
break;
case VLC_FOURCC('Y','U','Y','V'):
params.inputChromaFormat = XDM_YUV_422IBE; /* FIXME ? */
break;
case VLC_FOURCC('U','Y','V','Y'):
params.inputChromaFormat = XDM_YUV_422ILE; /* FIXME ? */
break;
case VLC_FOURCC('G','R','E','Y'):
params.inputChromaFormat = XDM_GRAY;
break;
#if 0
/* FIXME: not sure about this one */
case VLC_FOURCC('R','V','2','4'):
case VLC_FOURCC('R','V','3','2'):
params.inputChromaFormat = XDM_RGB;
break;
#endif
default:
msg_Err( p_enc, "Unsupported input chroma (%4.4s).",
(const char *)&p_enc->fmt_in.video.i_chroma );
goto error;
......@@ -180,11 +170,15 @@ int OpenVideoEncoder( vlc_object_t *p_this )
/* Holy bananas! We made it! */
msg_Info( p_enc, "Woohoooooooo!" );
free( psz_codec );
free( psz_engine );
return VLC_SUCCESS;
error:
if( p_sys->e ) Engine_close( p_sys->e );
free( p_sys );
free( psz_codec );
free( psz_engine );
return VLC_EGENERIC;
}
......
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