Commit 32b1ecb5 authored by Jean-Paul Saman's avatar Jean-Paul Saman

Revert "transcode: rewrite transcode_audio_process"

This reverts commit 3e1c59ce.
parent 9b46ee02
/*****************************************************************************
* transcode.c: transcoding stream output module
*****************************************************************************
* Copyright (C) 2003-2009 the VideoLAN team
* Copyright (C) 2003-2008 the VideoLAN team
* $Id$
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Gildas Bazin <gbazin@videolan.org>
* Jean-Paul Saman <jean-paul.saman at m2x dot nl>
* Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
* Antoine Cellerier <dionoea at videolan dot org>
*
* This program is free software; you can redistribute it and/or modify
......@@ -254,7 +254,7 @@ static int Del ( sout_stream_t *, sout_stream_id_t * );
static int Send( sout_stream_t *, sout_stream_id_t *, block_t* );
static int transcode_audio_new ( sout_stream_t *, sout_stream_id_t * );
static void transcode_audio_close ( sout_stream_t *, sout_stream_id_t * );
static void transcode_audio_close ( sout_stream_id_t * );
static int transcode_audio_process( sout_stream_t *, sout_stream_id_t *,
block_t *, block_t ** );
......@@ -286,9 +286,7 @@ static void transcode_osd_close ( sout_stream_t *, sout_stream_id_t * );
static int transcode_osd_process( sout_stream_t *, sout_stream_id_t *,
block_t *, block_t ** );
static void* VideoEncoderThread( vlc_object_t * p_this );
static void* AudioThread( vlc_object_t * p_this );
static void* EncoderThread( vlc_object_t * p_this );
static const int pi_channels_maps[6] =
{
......@@ -307,27 +305,29 @@ static const int pi_channels_maps[6] =
#define ENC_FRAMERATE (25 * 1000 + .5)
#define ENC_FRAMERATE_BASE 1000
typedef struct sout_stream_video_t sout_stream_video_t;
typedef struct sout_stream_audio_t sout_stream_audio_t;
struct sout_stream_video_t
struct sout_stream_sys_t
{
VLC_COMMON_MEMBERS
sout_stream_id_t *id;
#if 0
picture_fifo_t *pic_empty;
picture_fifo_t *pic_fifo;
block_fifo_t *fifo_in;
block_fifo_t *fifo_out;
#endif
sout_stream_t *p_out;
sout_stream_id_t *id_video;
block_t *p_buffers;
vlc_mutex_t lock_out;
vlc_cond_t cond;
picture_t * pp_pics[PICTURE_RING_SIZE];
int i_first_pic, i_last_pic;
/* Audio */
vlc_fourcc_t i_acodec; /* codec audio (0 if not transcode) */
char *psz_aenc;
config_chain_t *p_audio_cfg;
uint32_t i_sample_rate;
uint32_t i_channels;
int i_abitrate;
char *psz_af2;
/* Video */
vlc_fourcc_t i_vcodec; /* codec video (0 if not transcode) */
char *psz_venc;
config_chain_t *p_video_cfg;
......@@ -336,49 +336,15 @@ struct sout_stream_video_t
double f_fps;
unsigned int i_width, i_maxwidth;
unsigned int i_height, i_maxheight;
bool b_deinterlace;
char *psz_deinterlace;
config_chain_t *p_deinterlace_cfg;
int i_threads;
bool b_high_priority;
bool b_hurry_up;
char *psz_vf2;
sout_stream_sys_t *p_sys;
};
struct sout_stream_audio_t
{
VLC_COMMON_MEMBERS
sout_stream_id_t *id;
block_fifo_t *fifo_in;
block_fifo_t *fifo_out;
vlc_fourcc_t i_acodec; /* codec audio (0 if not transcode) */
char *psz_aenc;
config_chain_t *p_audio_cfg;
uint32_t i_sample_rate;
uint32_t i_channels;
int i_abitrate;
char *psz_af2;
sout_stream_sys_t *p_sys;
};
struct sout_stream_sys_t
{
sout_stream_t *p_out;
/* Video */
sout_stream_video_t *p_video;
/* Audio */
sout_stream_audio_t *p_audio;
/* SPU */
vlc_fourcc_t i_scodec; /* codec spu (0 if not transcode) */
char *psz_senc;
......@@ -392,10 +358,6 @@ struct sout_stream_sys_t
config_chain_t *p_osd_cfg;
bool b_osd; /* true when osd es is registered */
/* Misc. */
bool b_high_priority;
bool b_hurry_up;
/* Sync */
bool b_master_sync;
mtime_t i_master_drift;
......@@ -406,7 +368,6 @@ struct decoder_owner_sys_t
picture_t *pp_pics[PICTURE_RING_SIZE];
sout_stream_sys_t *p_sys;
};
struct filter_owner_sys_t
{
picture_t *pp_pics[PICTURE_RING_SIZE];
......@@ -420,39 +381,18 @@ static int Open( vlc_object_t *p_this )
{
sout_stream_t *p_stream = (sout_stream_t*)p_this;
sout_stream_sys_t *p_sys;
sout_stream_audio_t *p_audio;
sout_stream_video_t *p_video;
vlc_value_t val;
p_sys = (sout_stream_sys_t *)calloc( 1, sizeof( sout_stream_sys_t ) );
if( !p_sys ) return VLC_ENOMEM;
p_sys = vlc_object_create( p_this, sizeof( sout_stream_sys_t ) );
p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next );
if( !p_sys->p_out )
{
msg_Err( p_stream, "cannot create chain" );
free( p_sys );
vlc_object_release( p_sys );
return VLC_EGENERIC;
}
p_sys->p_audio = p_audio = vlc_object_create( p_this, sizeof( sout_stream_audio_t ) );
if( !p_audio )
{
free( p_sys );
return VLC_ENOMEM;
}
p_sys->p_video = p_video = vlc_object_create( p_this, sizeof( sout_stream_video_t ) );
if( !p_video )
{
vlc_object_release( p_audio );
free( p_sys );
return VLC_ENOMEM;
}
p_video->p_sys = p_sys;
p_audio->p_sys = p_sys;
p_sys->i_master_drift = 0;
config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
......@@ -460,145 +400,143 @@ static int Open( vlc_object_t *p_this )
/* Audio transcoding parameters */
var_Get( p_stream, SOUT_CFG_PREFIX "aenc", &val );
p_audio->psz_aenc = NULL;
p_audio->p_audio_cfg = NULL;
p_sys->psz_aenc = NULL;
p_sys->p_audio_cfg = NULL;
if( val.psz_string && *val.psz_string )
{
char *psz_next;
psz_next = config_ChainCreate( &p_audio->psz_aenc, &p_audio->p_audio_cfg,
psz_next = config_ChainCreate( &p_sys->psz_aenc, &p_sys->p_audio_cfg,
val.psz_string );
free( psz_next );
}
free( val.psz_string );
var_Get( p_stream, SOUT_CFG_PREFIX "acodec", &val );
p_audio->i_acodec = 0;
p_sys->i_acodec = 0;
if( val.psz_string && *val.psz_string )
{
char fcc[4] = " ";
memcpy( fcc, val.psz_string, __MIN( strlen( val.psz_string ), 4 ) );
p_audio->i_acodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] );
p_sys->i_acodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] );
}
free( val.psz_string );
var_Get( p_stream, SOUT_CFG_PREFIX "ab", &val );
p_audio->i_abitrate = val.i_int;
if( p_audio->i_abitrate < 4000 )
p_audio->i_abitrate *= 1000;
p_sys->i_abitrate = val.i_int;
if( p_sys->i_abitrate < 4000 ) p_sys->i_abitrate *= 1000;
var_Get( p_stream, SOUT_CFG_PREFIX "samplerate", &val );
p_audio->i_sample_rate = val.i_int;
p_sys->i_sample_rate = val.i_int;
var_Get( p_stream, SOUT_CFG_PREFIX "channels", &val );
p_audio->i_channels = val.i_int;
p_sys->i_channels = val.i_int;
if( p_audio->i_acodec )
if( p_sys->i_acodec )
{
if( p_audio->i_acodec == VLC_FOURCC('m','p','3',0) &&
p_audio->i_channels > 2 )
if( p_sys->i_acodec == VLC_FOURCC('m','p','3',0) &&
p_sys->i_channels > 2 )
{
msg_Warn( p_stream, "%d channels invalid for mp3, forcing to 2",
p_audio->i_channels );
p_audio->i_channels = 2;
p_sys->i_channels );
p_sys->i_channels = 2;
}
msg_Dbg( p_stream, "codec audio=%4.4s %dHz %d channels %dKb/s",
(char *)&p_audio->i_acodec, p_audio->i_sample_rate,
p_audio->i_channels, p_audio->i_abitrate / 1000 );
(char *)&p_sys->i_acodec, p_sys->i_sample_rate,
p_sys->i_channels, p_sys->i_abitrate / 1000 );
}
var_Get( p_stream, SOUT_CFG_PREFIX "afilter", &val );
if( val.psz_string && *val.psz_string )
p_audio->psz_af2 = val.psz_string;
p_sys->psz_af2 = val.psz_string;
else
{
free( val.psz_string );
p_audio->psz_af2 = NULL;
p_sys->psz_af2 = NULL;
}
/* Video transcoding parameters */
var_Get( p_stream, SOUT_CFG_PREFIX "venc", &val );
p_video->psz_venc = NULL;
p_video->p_video_cfg = NULL;
p_sys->psz_venc = NULL;
p_sys->p_video_cfg = NULL;
if( val.psz_string && *val.psz_string )
{
char *psz_next;
psz_next = config_ChainCreate( &p_video->psz_venc,
&p_video->p_video_cfg, val.psz_string );
psz_next = config_ChainCreate( &p_sys->psz_venc, &p_sys->p_video_cfg,
val.psz_string );
free( psz_next );
}
free( val.psz_string );
var_Get( p_stream, SOUT_CFG_PREFIX "vcodec", &val );
p_video->i_vcodec = 0;
p_sys->i_vcodec = 0;
if( val.psz_string && *val.psz_string )
{
char fcc[4] = " ";
memcpy( fcc, val.psz_string, __MIN( strlen( val.psz_string ), 4 ) );
p_video->i_vcodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] );
p_sys->i_vcodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] );
}
free( val.psz_string );
var_Get( p_stream, SOUT_CFG_PREFIX "vb", &val );
p_video->i_vbitrate = val.i_int;
if( p_video->i_vbitrate < 16000 )
p_video->i_vbitrate *= 1000;
p_sys->i_vbitrate = val.i_int;
if( p_sys->i_vbitrate < 16000 ) p_sys->i_vbitrate *= 1000;
var_Get( p_stream, SOUT_CFG_PREFIX "scale", &val );
p_video->f_scale = val.f_float;
p_sys->f_scale = val.f_float;
var_Get( p_stream, SOUT_CFG_PREFIX "fps", &val );
p_video->f_fps = val.f_float;
p_sys->f_fps = val.f_float;
var_Get( p_stream, SOUT_CFG_PREFIX "hurry-up", &val );
p_sys->b_hurry_up = val.b_bool;
var_Get( p_stream, SOUT_CFG_PREFIX "width", &val );
p_video->i_width = val.i_int;
p_sys->i_width = val.i_int;
var_Get( p_stream, SOUT_CFG_PREFIX "height", &val );
p_video->i_height = val.i_int;
p_sys->i_height = val.i_int;
var_Get( p_stream, SOUT_CFG_PREFIX "maxwidth", &val );
p_video->i_maxwidth = val.i_int;
p_sys->i_maxwidth = val.i_int;
var_Get( p_stream, SOUT_CFG_PREFIX "maxheight", &val );
p_video->i_maxheight = val.i_int;
p_sys->i_maxheight = val.i_int;
var_Get( p_stream, SOUT_CFG_PREFIX "vfilter", &val );
if( val.psz_string && *val.psz_string )
p_video->psz_vf2 = val.psz_string;
p_sys->psz_vf2 = val.psz_string;
else
{
free( val.psz_string );
p_video->psz_vf2 = NULL;
p_sys->psz_vf2 = NULL;
}
var_Get( p_stream, SOUT_CFG_PREFIX "deinterlace", &val );
p_video->b_deinterlace = val.b_bool;
p_sys->b_deinterlace = val.b_bool;
var_Get( p_stream, SOUT_CFG_PREFIX "deinterlace-module", &val );
p_video->psz_deinterlace = NULL;
p_video->p_deinterlace_cfg = NULL;
p_sys->psz_deinterlace = NULL;
p_sys->p_deinterlace_cfg = NULL;
if( val.psz_string && *val.psz_string )
{
char *psz_next;
psz_next = config_ChainCreate( &p_video->psz_deinterlace,
&p_video->p_deinterlace_cfg,
psz_next = config_ChainCreate( &p_sys->psz_deinterlace,
&p_sys->p_deinterlace_cfg,
val.psz_string );
free( psz_next );
}
free( val.psz_string );
var_Get( p_stream, SOUT_CFG_PREFIX "threads", &val );
p_video->i_threads = val.i_int;
p_sys->i_threads = val.i_int;
var_Get( p_stream, SOUT_CFG_PREFIX "high-priority", &val );
p_sys->b_high_priority = val.b_bool;
if( p_video->i_vcodec )
if( p_sys->i_vcodec )
{
msg_Dbg( p_stream, "codec video=%4.4s %dx%d scaling: %f %dkb/s",
(char *)&p_video->i_vcodec, p_video->i_width, p_video->i_height,
p_video->f_scale, p_video->i_vbitrate / 1000 );
(char *)&p_sys->i_vcodec, p_sys->i_width, p_sys->i_height,
p_sys->f_scale, p_sys->i_vbitrate / 1000 );
}
/* Subpictures transcoding parameters */
......@@ -684,7 +622,7 @@ static int Open( vlc_object_t *p_this )
/* Audio settings */
var_Get( p_stream, SOUT_CFG_PREFIX "audio-sync", &val );
p_sys->b_master_sync = val.b_bool;
if( p_video->f_fps > 0 ) p_sys->b_master_sync = true;
if( p_sys->f_fps > 0 ) p_sys->b_master_sync = true;
p_stream->pf_add = Add;
p_stream->pf_del = Del;
......@@ -701,23 +639,21 @@ 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;
sout_stream_audio_t *p_audio = p_sys->p_audio;
sout_stream_video_t *p_video = p_sys->p_video;
sout_StreamDelete( p_sys->p_out );
free( p_audio->psz_af2 );
free( p_sys->psz_af2 );
config_ChainDestroy( p_audio->p_audio_cfg );
free( p_audio->psz_aenc );
config_ChainDestroy( p_sys->p_audio_cfg );
free( p_sys->psz_aenc );
free( p_video->psz_vf2 );
free( p_sys->psz_vf2 );
config_ChainDestroy( p_video->p_video_cfg );
free( p_video->psz_venc );
config_ChainDestroy( p_sys->p_video_cfg );
free( p_sys->psz_venc );
config_ChainDestroy( p_video->p_deinterlace_cfg );
free( p_video->psz_deinterlace );
config_ChainDestroy( p_sys->p_deinterlace_cfg );
free( p_sys->psz_deinterlace );
config_ChainDestroy( p_sys->p_spu_cfg );
free( p_sys->psz_senc );
......@@ -727,9 +663,7 @@ static void Close( vlc_object_t * p_this )
config_ChainDestroy( p_sys->p_osd_cfg );
free( p_sys->psz_osdenc );
vlc_object_release( p_audio );
vlc_object_release( p_video );
free( p_sys );
vlc_object_release( p_sys );
}
struct sout_stream_id_t
......@@ -757,8 +691,6 @@ struct sout_stream_id_t
static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
sout_stream_audio_t *p_audio = p_sys->p_audio;
sout_stream_video_t *p_video = p_sys->p_video;
sout_stream_id_t *id;
id = calloc( 1, sizeof( sout_stream_id_t ) );
......@@ -792,22 +724,21 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
if( p_fmt->psz_language )
id->p_encoder->fmt_out.psz_language = strdup( p_fmt->psz_language );
if( p_fmt->i_cat == AUDIO_ES &&
(p_audio->i_acodec || p_audio->psz_aenc) )
if( p_fmt->i_cat == AUDIO_ES && (p_sys->i_acodec || p_sys->psz_aenc) )
{
msg_Dbg( p_stream,
"creating audio transcoding from fcc=`%4.4s' to fcc=`%4.4s'",
(char*)&p_fmt->i_codec, (char*)&p_audio->i_acodec );
(char*)&p_fmt->i_codec, (char*)&p_sys->i_acodec );
/* Complete destination format */
id->p_encoder->fmt_out.i_codec = p_audio->i_acodec;
id->p_encoder->fmt_out.audio.i_rate = p_audio->i_sample_rate > 0 ?
p_audio->i_sample_rate : p_fmt->audio.i_rate;
id->p_encoder->fmt_out.i_bitrate = p_audio->i_abitrate;
id->p_encoder->fmt_out.i_codec = p_sys->i_acodec;
id->p_encoder->fmt_out.audio.i_rate = p_sys->i_sample_rate > 0 ?
p_sys->i_sample_rate : p_fmt->audio.i_rate;
id->p_encoder->fmt_out.i_bitrate = p_sys->i_abitrate;
id->p_encoder->fmt_out.audio.i_bitspersample =
p_fmt->audio.i_bitspersample;
id->p_encoder->fmt_out.audio.i_channels = p_audio->i_channels > 0 ?
p_audio->i_channels : p_fmt->audio.i_channels;
id->p_encoder->fmt_out.audio.i_channels = p_sys->i_channels > 0 ?
p_sys->i_channels : p_fmt->audio.i_channels;
/* Sanity check for audio channels */
id->p_encoder->fmt_out.audio.i_channels =
__MIN( id->p_encoder->fmt_out.audio.i_channels,
......@@ -839,24 +770,24 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
if( !id->id )
{
transcode_audio_close( p_stream, id );
transcode_audio_close( id );
goto error;
}
date_Init( &id->interpolated_pts, p_fmt->audio.i_rate, 1 );
}
else if( p_fmt->i_cat == VIDEO_ES &&
(p_video->i_vcodec != 0 || p_video->psz_venc) )
(p_sys->i_vcodec != 0 || p_sys->psz_venc) )
{
msg_Dbg( p_stream,
"creating video transcoding from fcc=`%4.4s' to fcc=`%4.4s'",
(char*)&p_fmt->i_codec, (char*)&p_video->i_vcodec );
(char*)&p_fmt->i_codec, (char*)&p_sys->i_vcodec );
/* Complete destination format */
id->p_encoder->fmt_out.i_codec = p_video->i_vcodec;
id->p_encoder->fmt_out.video.i_width = p_video->i_width & ~1;
id->p_encoder->fmt_out.video.i_height = p_video->i_height & ~1;
id->p_encoder->fmt_out.i_bitrate = p_video->i_vbitrate;
id->p_encoder->fmt_out.i_codec = p_sys->i_vcodec;
id->p_encoder->fmt_out.video.i_width = p_sys->i_width & ~1;
id->p_encoder->fmt_out.video.i_height = p_sys->i_height & ~1;
id->p_encoder->fmt_out.i_bitrate = p_sys->i_vbitrate;
/* Build decoder -> filter -> encoder chain */
if( transcode_video_new( p_stream, id ) )
......@@ -869,10 +800,10 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
* all the characteristics of the decoded stream yet */
id->b_transcode = true;
if( p_video->f_fps > 0 )
if( p_sys->f_fps > 0 )
{
id->p_encoder->fmt_out.video.i_frame_rate =
(p_video->f_fps * 1000) + 0.5;
(p_sys->f_fps * 1000) + 0.5;
id->p_encoder->fmt_out.video.i_frame_rate_base =
ENC_FRAMERATE_BASE;
}
......@@ -978,7 +909,7 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
switch( id->p_decoder->fmt_in.i_cat )
{
case AUDIO_ES:
transcode_audio_close( p_stream, id );
transcode_audio_close( id );
break;
case VIDEO_ES:
transcode_video_close( p_stream, id );
......@@ -1133,7 +1064,6 @@ static bool transcode_audio_filter_needed( const es_format_t *p_fmt1, const es_f
return true;
return false;
}
static int transcode_audio_filter_chain_build( sout_stream_t *p_stream, filter_chain_t *p_chain,
const es_format_t *p_dst, const es_format_t *p_src )
{
......@@ -1229,17 +1159,16 @@ static int transcode_audio_new( sout_stream_t *p_stream,
sout_stream_id_t *id )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
sout_stream_audio_t *p_audio = p_sys->p_audio;
es_format_t fmt_last;
int i_priority;
/*
* Open decoder
*/
/* Initialization of decoder structures */
id->p_decoder->fmt_out = id->p_decoder->fmt_in;
id->p_decoder->fmt_out.i_extra = 0;
id->p_decoder->fmt_out.p_extra = NULL;
id->p_decoder->fmt_out.p_extra = 0;
id->p_decoder->pf_decode_audio = NULL;
id->p_decoder->pf_aout_buffer_new = audio_new_buffer;
id->p_decoder->pf_aout_buffer_del = audio_del_buffer;
......@@ -1254,9 +1183,7 @@ static int transcode_audio_new( sout_stream_t *p_stream,
}
id->p_decoder->fmt_out.audio.i_bitspersample =
aout_BitsPerSample( id->p_decoder->fmt_out.i_codec );
fmt_last = id->p_decoder->fmt_out;
/* Fix AAC SBR changing number of channels and sampling rate */
if( !(id->p_decoder->fmt_in.i_codec == VLC_FOURCC('m','p','4','a') &&
fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate &&
......@@ -1266,6 +1193,7 @@ static int transcode_audio_new( sout_stream_t *p_stream,
/*
* Open encoder
*/
/* Initialization of encoder format structures */
es_format_Init( &id->p_encoder->fmt_in, id->p_decoder->fmt_in.i_cat,
id->p_decoder->fmt_out.i_codec );
......@@ -1281,48 +1209,24 @@ static int transcode_audio_new( sout_stream_t *p_stream,
id->p_encoder->fmt_in.audio.i_bitspersample =
aout_BitsPerSample( id->p_encoder->fmt_in.i_codec );
id->p_encoder->p_cfg = p_audio->p_audio_cfg;
id->p_encoder->p_cfg = p_stream->p_sys->p_audio_cfg;
id->p_encoder->p_module =
module_need( id->p_encoder, "encoder", p_audio->psz_aenc, true );
module_need( id->p_encoder, "encoder", p_sys->psz_aenc, true );
if( !id->p_encoder->p_module )
{
msg_Err( p_stream, "cannot find audio encoder (module:%s fourcc:%4.4s)",
p_audio->psz_aenc ? p_audio->psz_aenc : "any",
(char *)&p_audio->i_acodec );
p_sys->psz_aenc ? p_sys->psz_aenc : "any",
(char *)&p_sys->i_acodec );
module_unneed( id->p_decoder, id->p_decoder->p_module );
id->p_decoder->p_module = NULL;
return VLC_EGENERIC;
}
id->p_encoder->fmt_in.audio.i_format = id->p_encoder->fmt_in.i_codec;
id->p_encoder->fmt_in.audio.i_bitspersample =
aout_BitsPerSample( id->p_encoder->fmt_in.i_codec );
i_priority = p_sys->b_high_priority ? VLC_THREAD_PRIORITY_OUTPUT :
VLC_THREAD_PRIORITY_AUDIO;
p_audio->id = id;
p_audio->b_die = p_audio->b_error = 0;
p_audio->fifo_in = block_FifoNew();
p_audio->fifo_out = block_FifoNew();
if( !p_audio->fifo_in || !p_audio->fifo_out )
{
module_unneed( id->p_decoder, id->p_decoder->p_module );
id->p_decoder->p_module = NULL;
free( id->p_decoder->p_owner );
if( p_audio->fifo_in )
block_FifoRelease( p_audio->fifo_in );
return VLC_ENOMEM;
}
if( vlc_thread_create( p_audio, "audio", AudioThread, i_priority ) )
{
msg_Err( p_stream, "cannot spawn encoder thread" );
module_unneed( id->p_decoder, id->p_decoder->p_module );
id->p_decoder->p_module = NULL;
free( id->p_decoder->p_owner );
block_FifoRelease( p_audio->fifo_in );
block_FifoRelease( p_audio->fifo_out );
return VLC_EGENERIC;
}
/* Load user specified audio filters */
if( p_audio->psz_af2 )
if( p_sys->psz_af2 )
{
es_format_t fmt_fl32 = fmt_last;
fmt_fl32.i_codec =
......@@ -1331,11 +1235,7 @@ static int transcode_audio_new( sout_stream_t *p_stream,
if( transcode_audio_filter_chain_build( p_stream, id->p_uf_chain,
&fmt_fl32, &fmt_last ) )
{
vlc_object_kill( p_audio );
block_FifoWake( p_audio->fifo_in );
block_FifoWake( p_audio->fifo_out );
vlc_thread_join( p_audio );
transcode_audio_close( p_stream, id );
transcode_audio_close( id );
return VLC_EGENERIC;
}
fmt_last = fmt_fl32;
......@@ -1343,7 +1243,7 @@ static int transcode_audio_new( sout_stream_t *p_stream,
id->p_uf_chain = filter_chain_New( p_stream, "audio filter2", false,
transcode_audio_filter_allocation_init, NULL, NULL );
filter_chain_Reset( id->p_uf_chain, &fmt_last, &fmt_fl32 );
if( filter_chain_AppendFromString( id->p_uf_chain, p_audio->psz_af2 ) > 0 )
if( filter_chain_AppendFromString( id->p_uf_chain, p_sys->psz_af2 ) > 0 )
fmt_last = *filter_chain_GetFmtOut( id->p_uf_chain );
}
......@@ -1355,7 +1255,7 @@ static int transcode_audio_new( sout_stream_t *p_stream,
if( transcode_audio_filter_chain_build( p_stream, id->p_f_chain,
&id->p_encoder->fmt_in, &fmt_last ) )
{
transcode_audio_close( p_stream, id );
transcode_audio_close( id );
return VLC_EGENERIC;
}
fmt_last = id->p_encoder->fmt_in;
......@@ -1367,17 +1267,10 @@ static int transcode_audio_new( sout_stream_t *p_stream,
return VLC_SUCCESS;
}
static void transcode_audio_close( sout_stream_t *p_stream, sout_stream_id_t *id )
static void transcode_audio_close( sout_stream_id_t *id )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
audio_timer_close( id->p_encoder );
vlc_object_kill( p_sys->p_audio );
block_FifoWake( p_sys->p_audio->fifo_in );
block_FifoWake( p_sys->p_audio->fifo_out );
vlc_thread_join( p_sys->p_audio );
/* Close decoder */
if( id->p_decoder->p_module )
module_unneed( id->p_decoder, id->p_decoder->p_module );
......@@ -1397,10 +1290,6 @@ static void transcode_audio_close( sout_stream_t *p_stream, sout_stream_id_t *id
filter_chain_Delete( id->p_uf_chain );
if( id->p_f_chain )
filter_chain_Delete( id->p_f_chain );
/* Release fifo's */
block_FifoRelease( p_sys->p_audio->fifo_in );
block_FifoRelease( p_sys->p_audio->fifo_out );
}
static int transcode_audio_process( sout_stream_t *p_stream,
......@@ -1408,49 +1297,13 @@ static int transcode_audio_process( sout_stream_t *p_stream,
block_t *in, block_t **out )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
VLC_UNUSED(id);
*out = NULL;
block_FifoPut( p_sys->p_audio->fifo_in, in );
while( block_FifoCount( p_sys->p_audio->fifo_out ) > 0 )
{
block_t *p_block = block_FifoGet( p_sys->p_audio->fifo_out );
if( !p_block )
break;
block_ChainAppend( out, p_block );
}
return VLC_SUCCESS;
}
static void* AudioThread( vlc_object_t* p_this )
{
sout_stream_audio_t *p_audio = (sout_stream_audio_t*)p_this;
sout_stream_sys_t *p_sys = p_audio->p_sys;
sout_stream_t *p_stream = p_sys->p_out;
sout_stream_id_t *id = p_audio->id;
int canc = vlc_savecancel ();
while( vlc_object_alive (p_audio) && !p_audio->b_error )
{
aout_buffer_t *p_audio_buf;
block_t *p_block, *p_audio_block;
block_t *in;
do {
in = block_FifoGet( p_audio->fifo_in );
if( !vlc_object_alive (p_audio) || p_audio->b_error )
goto cleanup;
} while( !in );
*out = NULL;
while( (p_audio_buf = id->p_decoder->pf_decode_audio( id->p_decoder, &in )) )
while( (p_audio_buf = id->p_decoder->pf_decode_audio( id->p_decoder,
&in )) )
{
if( !vlc_object_alive (p_audio) || p_audio->b_error )
{
free( p_audio_buf );
goto cleanup;
}
sout_UpdateStatistic( p_stream->p_sout, SOUT_STATISTIC_DECODED_AUDIO, 1 );
if( p_sys->b_master_sync )
{
......@@ -1458,7 +1311,7 @@ static void* AudioThread( vlc_object_t* p_this )
if ( p_audio_buf->start_date - i_dts > MASTER_SYNC_MAX_DRIFT
|| p_audio_buf->start_date - i_dts < -MASTER_SYNC_MAX_DRIFT )
{
msg_Dbg( p_this, "drift is too high, resetting master sync" );
msg_Dbg( p_stream, "drift is too high, resetting master sync" );
date_Set( &id->interpolated_pts, p_audio_buf->start_date );
i_dts = p_audio_buf->start_date + 1;
}
......@@ -1496,18 +1349,12 @@ static void* AudioThread( vlc_object_t* p_this )
p_block = id->p_encoder->pf_encode_audio( id->p_encoder, p_audio_buf );
audio_timer_stop( id->p_encoder );
block_FifoPut( p_audio->fifo_out, p_block );
block_ChainAppend( out, p_block );
block_Release( p_audio_block );
free( p_audio_buf );
}
}
cleanup:
block_FifoEmpty( p_audio->fifo_in );
block_FifoEmpty( p_audio->fifo_out );
vlc_restorecancel (canc);
return NULL;
return VLC_SUCCESS;
}
static void audio_release_buffer( aout_buffer_t *p_buffer )
......@@ -1524,7 +1371,7 @@ static aout_buffer_t *audio_new_buffer( decoder_t *p_dec, int i_samples )
if( p_dec->fmt_out.audio.i_bitspersample )
{
i_size = ((i_samples * p_dec->fmt_out.audio.i_bitspersample) >> 3) *
i_size = i_samples * p_dec->fmt_out.audio.i_bitspersample / 8 *
p_dec->fmt_out.audio.i_channels;
}
else if( p_dec->fmt_out.audio.i_bytes_per_frame &&
......@@ -1543,11 +1390,7 @@ static aout_buffer_t *audio_new_buffer( decoder_t *p_dec, int i_samples )
p_buffer->b_discontinuity = false;
p_buffer->pf_release = audio_release_buffer;
p_buffer->p_sys = p_block = block_New( p_dec, i_size );
if( !p_block )
{
free( p_buffer );
return NULL;
}
p_buffer->p_buffer = p_block->p_buffer;
p_buffer->i_size = p_buffer->i_nb_bytes = p_block->i_buffer;
p_buffer->i_nb_samples = i_samples;
......@@ -1604,7 +1447,6 @@ static void transcode_video_filter_allocation_clear( filter_t *p_filter )
static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
sout_stream_video_t *p_video = p_sys->p_video;
int i;
/* Open decoder
......@@ -1627,7 +1469,7 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
for( i = 0; i < PICTURE_RING_SIZE; i++ )
id->p_decoder->p_owner->pp_pics[i] = NULL;
id->p_decoder->p_owner->p_sys = p_sys;
/* id->p_decoder->p_cfg = p_video->p_video_cfg; */
/* id->p_decoder->p_cfg = p_sys->p_video_cfg; */
id->p_decoder->p_module =
module_need( id->p_decoder, "decoder", "$codec", false );
......@@ -1666,18 +1508,18 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
id->p_encoder->fmt_in.video.i_frame_rate = ENC_FRAMERATE;
id->p_encoder->fmt_in.video.i_frame_rate_base = ENC_FRAMERATE_BASE;
id->p_encoder->i_threads = p_video->i_threads;
id->p_encoder->p_cfg = p_video->p_video_cfg;
id->p_encoder->i_threads = p_sys->i_threads;
id->p_encoder->p_cfg = p_sys->p_video_cfg;
id->p_encoder->p_module =
module_need( id->p_encoder, "encoder", p_video->psz_venc, true );
module_need( id->p_encoder, "encoder", p_sys->psz_venc, true );
if( !id->p_encoder->p_module )
{
msg_Err( p_stream, "cannot find video encoder (module:%s fourcc:%4.4s)",
p_video->psz_venc ? p_video->psz_venc : "any",
(char *)&p_video->i_vcodec );
p_sys->psz_venc ? p_sys->psz_venc : "any",
(char *)&p_sys->i_vcodec );
module_unneed( id->p_decoder, id->p_decoder->p_module );
id->p_decoder->p_module = NULL;
id->p_decoder->p_module = 0;
free( id->p_decoder->p_owner );
return VLC_EGENERIC;
}
......@@ -1693,23 +1535,23 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
}
id->p_encoder->p_module = NULL;
if( p_video->i_threads >= 1 )
if( p_sys->i_threads >= 1 )
{
int i_priority = p_sys->b_high_priority ? VLC_THREAD_PRIORITY_OUTPUT :
VLC_THREAD_PRIORITY_VIDEO;
p_video->id = id;
vlc_mutex_init( &p_video->lock_out );
vlc_cond_init( &p_video->cond );
memset( p_video->pp_pics, 0, sizeof(p_video->pp_pics) );
p_video->i_first_pic = 0;
p_video->i_last_pic = 0;
p_video->p_buffers = NULL;
p_video->b_die = p_video->b_error = 0;
if( vlc_thread_create( p_video, "video encoder", VideoEncoderThread, i_priority ) )
p_sys->id_video = id;
vlc_mutex_init( &p_sys->lock_out );
vlc_cond_init( &p_sys->cond );
memset( p_sys->pp_pics, 0, sizeof(p_sys->pp_pics) );
p_sys->i_first_pic = 0;
p_sys->i_last_pic = 0;
p_sys->p_buffers = NULL;
p_sys->b_die = p_sys->b_error = 0;
if( vlc_thread_create( p_sys, "encoder", EncoderThread, i_priority ) )
{
msg_Err( p_stream, "cannot spawn encoder thread" );
module_unneed( id->p_decoder, id->p_decoder->p_module );
id->p_decoder->p_module = NULL;
id->p_decoder->p_module = 0;
free( id->p_decoder->p_owner );
return VLC_EGENERIC;
}
......@@ -1722,7 +1564,6 @@ static void transcode_video_encoder_init( sout_stream_t *p_stream,
sout_stream_id_t *id )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
sout_stream_video_t *p_video = p_sys->p_video;
/* Calculate scaling
* width/height of source */
......@@ -1750,12 +1591,12 @@ static void transcode_video_encoder_init( sout_stream_t *p_stream,
/* Calculate scaling factor for specified parameters */
if( id->p_encoder->fmt_out.video.i_width <= 0 &&
id->p_encoder->fmt_out.video.i_height <= 0 && p_video->f_scale )
id->p_encoder->fmt_out.video.i_height <= 0 && p_sys->f_scale )
{
/* Global scaling. Make sure width will remain a factor of 16 */
float f_real_scale;
int i_new_height;
int i_new_width = i_src_width * p_video->f_scale;
int i_new_width = i_src_width * p_sys->f_scale;
if( i_new_width % 16 <= 7 && i_new_width >= 16 )
i_new_width -= i_new_width % 16;
......@@ -1793,16 +1634,16 @@ static void transcode_video_encoder_init( sout_stream_t *p_stream,
/* check maxwidth and maxheight
*/
if( p_video->i_maxwidth && f_scale_width >
(float)p_video->i_maxwidth / i_src_width )
if( p_sys->i_maxwidth && f_scale_width > (float)p_sys->i_maxwidth /
i_src_width )
{
f_scale_width = (float)p_video->i_maxwidth / i_src_width;
f_scale_width = (float)p_sys->i_maxwidth / i_src_width;
}
if( p_video->i_maxheight && f_scale_height >
(float)p_video->i_maxheight / i_src_height )
if( p_sys->i_maxheight && f_scale_height > (float)p_sys->i_maxheight /
i_src_height )
{
f_scale_height = (float)p_video->i_maxheight / i_src_height;
f_scale_height = (float)p_sys->i_maxheight / i_src_height;
}
/* Change aspect ratio from source pixel to scaled pixel */
......@@ -1883,19 +1724,19 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream,
sout_stream_id_t *id )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
sout_stream_video_t *p_video = p_sys->p_video;
msg_Dbg( p_stream, "destination (after video filters) %ix%i",
id->p_encoder->fmt_in.video.i_width,
id->p_encoder->fmt_in.video.i_height );
id->p_encoder->p_module =
module_need( id->p_encoder, "encoder", p_video->psz_venc, true );
module_need( id->p_encoder, "encoder", p_sys->psz_venc, true );
if( !id->p_encoder->p_module )
{
msg_Err( p_stream, "cannot find video encoder (module:%s fourcc:%4.4s)",
p_video->psz_venc ? p_video->psz_venc : "any",
(char *)&p_video->i_vcodec );
p_sys->psz_venc ? p_sys->psz_venc : "any",
(char *)&p_sys->i_vcodec );
return VLC_EGENERIC;
}
......@@ -1908,7 +1749,7 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream,
id->p_encoder->fmt_out.i_codec = VLC_FOURCC('m','p','g','v');
}
id->id = sout_StreamIdAdd( p_sys->p_out,
id->id = sout_StreamIdAdd( p_stream->p_sys->p_out,
&id->p_encoder->fmt_out );
if( !id->id )
{
......@@ -1922,19 +1763,17 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream,
static void transcode_video_close( sout_stream_t *p_stream,
sout_stream_id_t *id )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
sout_stream_video_t *p_video = p_sys->p_video;
int i;
if( p_video->i_threads >= 1 )
if( p_stream->p_sys->i_threads >= 1 )
{
vlc_mutex_lock( &p_video->lock_out );
vlc_object_kill( p_video );
vlc_cond_signal( &p_video->cond );
vlc_mutex_unlock( &p_video->lock_out );
vlc_thread_join( p_video );
vlc_mutex_destroy( &p_video->lock_out );
vlc_cond_destroy( &p_video->cond );
vlc_mutex_lock( &p_stream->p_sys->lock_out );
vlc_object_kill( p_stream->p_sys );
vlc_cond_signal( &p_stream->p_sys->cond );
vlc_mutex_unlock( &p_stream->p_sys->lock_out );
vlc_thread_join( p_stream->p_sys );
vlc_mutex_destroy( &p_stream->p_sys->lock_out );
vlc_cond_destroy( &p_stream->p_sys->cond );
}
video_timer_close( id->p_encoder );
......@@ -1973,7 +1812,6 @@ static int transcode_video_process( sout_stream_t *p_stream,
block_t *in, block_t **out )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
sout_stream_video_t *p_video = p_sys->p_video;
int i_duplicate = 1;
picture_t *p_pic, *p_pic2 = NULL;
*out = NULL;
......@@ -2046,11 +1884,11 @@ static int transcode_video_process( sout_stream_t *p_stream,
p_stream->p_sys );
/* Deinterlace */
if( p_video->b_deinterlace )
if( p_stream->p_sys->b_deinterlace )
{
filter_chain_AppendFilter( id->p_f_chain,
p_video->psz_deinterlace,
p_video->p_deinterlace_cfg,
p_sys->psz_deinterlace,
p_sys->p_deinterlace_cfg,
&id->p_decoder->fmt_out,
&id->p_decoder->fmt_out );
}
......@@ -2069,7 +1907,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
&id->p_encoder->fmt_in );
}
if( p_video->psz_vf2 )
if( p_sys->psz_vf2 )
{
const es_format_t *p_fmt_out;
id->p_uf_chain = filter_chain_New( p_stream, "video filter2",
......@@ -2079,7 +1917,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
p_stream->p_sys );
filter_chain_Reset( id->p_uf_chain, &id->p_encoder->fmt_in,
&id->p_encoder->fmt_in );
filter_chain_AppendFromString( id->p_uf_chain, p_video->psz_vf2 );
filter_chain_AppendFromString( id->p_uf_chain, p_sys->psz_vf2 );
p_fmt_out = filter_chain_GetFmtOut( id->p_uf_chain );
es_format_Copy( &id->p_encoder->fmt_in, p_fmt_out );
id->p_encoder->fmt_out.video.i_width =
......@@ -2149,7 +1987,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
if( id->p_uf_chain )
p_pic = filter_chain_VideoFilter( id->p_uf_chain, p_pic );
if( p_video->i_threads == 0 )
if( p_sys->i_threads == 0 )
{
block_t *p_block;
......@@ -2185,7 +2023,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
}
date_Increment( &id->interpolated_pts, 1 );
if( p_video->i_threads >= 1 )
if( p_sys->i_threads >= 1 )
{
/* We can't modify the picture, we need to duplicate it */
p_pic2 = video_new_buffer_decoder( id->p_decoder );
......@@ -2200,81 +2038,81 @@ static int transcode_video_process( sout_stream_t *p_stream,
block_t *p_block;
p_pic->date = i_pts;
video_timer_start( id->p_encoder );
p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic );
p_block = id->p_encoder->pf_encode_video(id->p_encoder, p_pic);
video_timer_stop( id->p_encoder );
block_ChainAppend( out, p_block );
}
}
if( p_video->i_threads == 0 )
if( p_sys->i_threads == 0 )
{
p_pic->pf_release( p_pic );
}
else
{
vlc_mutex_lock( &p_video->lock_out );
p_video->pp_pics[p_video->i_last_pic++] = p_pic;
p_video->i_last_pic %= PICTURE_RING_SIZE;
*out = p_video->p_buffers;
p_video->p_buffers = NULL;
vlc_mutex_lock( &p_sys->lock_out );
p_sys->pp_pics[p_sys->i_last_pic++] = p_pic;
p_sys->i_last_pic %= PICTURE_RING_SIZE;
*out = p_sys->p_buffers;
p_sys->p_buffers = NULL;
if( p_pic2 != NULL )
{
p_video->pp_pics[p_video->i_last_pic++] = p_pic2;
p_video->i_last_pic %= PICTURE_RING_SIZE;
p_sys->pp_pics[p_sys->i_last_pic++] = p_pic2;
p_sys->i_last_pic %= PICTURE_RING_SIZE;
}
vlc_cond_signal( &p_video->cond );
vlc_mutex_unlock( &p_video->lock_out );
vlc_cond_signal( &p_sys->cond );
vlc_mutex_unlock( &p_sys->lock_out );
}
}
return VLC_SUCCESS;
}
static void* VideoEncoderThread( vlc_object_t* p_this )
static void* EncoderThread( vlc_object_t* p_this )
{
sout_stream_video_t *p_video = (sout_stream_video_t*)p_this;
sout_stream_id_t *id = p_video->id;
sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_this;
sout_stream_id_t *id = p_sys->id_video;
picture_t *p_pic;
int canc = vlc_savecancel ();
while( vlc_object_alive (p_video) && !p_video->b_error )
while( vlc_object_alive (p_sys) && !p_sys->b_error )
{
block_t *p_block;
vlc_mutex_lock( &p_video->lock_out );
while( p_video->i_last_pic == p_video->i_first_pic )
vlc_mutex_lock( &p_sys->lock_out );
while( p_sys->i_last_pic == p_sys->i_first_pic )
{
vlc_cond_wait( &p_video->cond, &p_video->lock_out );
if( !vlc_object_alive (p_video) || p_video->b_error ) break;
vlc_cond_wait( &p_sys->cond, &p_sys->lock_out );
if( !vlc_object_alive (p_sys) || p_sys->b_error ) break;
}
if( !vlc_object_alive (p_video) || p_video->b_error )
if( !vlc_object_alive (p_sys) || p_sys->b_error )
{
vlc_mutex_unlock( &p_video->lock_out );
vlc_mutex_unlock( &p_sys->lock_out );
break;
}
p_pic = p_video->pp_pics[p_video->i_first_pic++];
p_video->i_first_pic %= PICTURE_RING_SIZE;
vlc_mutex_unlock( &p_video->lock_out );
p_pic = p_sys->pp_pics[p_sys->i_first_pic++];
p_sys->i_first_pic %= PICTURE_RING_SIZE;
vlc_mutex_unlock( &p_sys->lock_out );
video_timer_start( id->p_encoder );
p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic );
video_timer_stop( id->p_encoder );
vlc_mutex_lock( &p_video->lock_out );
block_ChainAppend( &p_video->p_buffers, p_block );
vlc_mutex_lock( &p_sys->lock_out );
block_ChainAppend( &p_sys->p_buffers, p_block );
vlc_mutex_unlock( &p_video->lock_out );
vlc_mutex_unlock( &p_sys->lock_out );
p_pic->pf_release( p_pic );
}
while( p_video->i_last_pic != p_video->i_first_pic )
while( p_sys->i_last_pic != p_sys->i_first_pic )
{
p_pic = p_video->pp_pics[p_video->i_first_pic++];
p_video->i_first_pic %= PICTURE_RING_SIZE;
p_pic = p_sys->pp_pics[p_sys->i_first_pic++];
p_sys->i_first_pic %= PICTURE_RING_SIZE;
p_pic->pf_release( p_pic );
}
block_ChainRelease( p_video->p_buffers );
block_ChainRelease( p_sys->p_buffers );
vlc_restorecancel (canc);
return NULL;
......@@ -2298,7 +2136,6 @@ static picture_t *video_new_buffer( vlc_object_t *p_this, picture_t **pp_ring,
sout_stream_sys_t *p_sys )
{
decoder_t *p_dec = (decoder_t *)p_this;
sout_stream_video_t *p_video = p_sys->p_video;
picture_t *p_pic;
int i;
......@@ -2316,14 +2153,14 @@ static picture_t *video_new_buffer( vlc_object_t *p_this, picture_t **pp_ring,
if( pp_ring[i] == NULL ) break;
}
if( i == PICTURE_RING_SIZE && p_video->i_threads >= 1 )
if( i == PICTURE_RING_SIZE && p_sys->i_threads >= 1 )
{
int i_first_pic = p_video->i_first_pic;
int i_first_pic = p_sys->i_first_pic;
if( p_video->i_first_pic != p_video->i_last_pic )
if( p_sys->i_first_pic != p_sys->i_last_pic )
{
/* Encoder still has stuff to encode, wait to clear-up the list */
while( p_video->i_first_pic == i_first_pic )
while( p_sys->i_first_pic == i_first_pic )
msleep( 5000 );
}
......
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