Commit 9e267491 authored by Gildas Bazin's avatar Gildas Bazin

* modules/stream_out/transcode.c: use picture ring buffers to avoid leaks due...

* modules/stream_out/transcode.c: use picture ring buffers to avoid leaks due to decoders not releasing pictures properly and to avoid uncessary mallocs.
parent f1db3087
...@@ -210,10 +210,13 @@ static int transcode_video_encoder_open( sout_stream_t *, sout_stream_id_t *); ...@@ -210,10 +210,13 @@ static int transcode_video_encoder_open( sout_stream_t *, sout_stream_id_t *);
static int transcode_video_process( sout_stream_t *, sout_stream_id_t *, static int transcode_video_process( sout_stream_t *, sout_stream_id_t *,
block_t *, block_t ** ); block_t *, block_t ** );
static picture_t *video_new_buffer( decoder_t * ); static void video_del_buffer( vlc_object_t *, picture_t * );
static void video_del_buffer( decoder_t *, picture_t * ); static picture_t *video_new_buffer_decoder( decoder_t * );
static void video_link_picture( decoder_t *, picture_t * ); static void video_del_buffer_decoder( decoder_t *, picture_t * );
static void video_unlink_picture( decoder_t *, picture_t * ); static void video_link_picture_decoder( decoder_t *, picture_t * );
static void video_unlink_picture_decoder( decoder_t *, picture_t * );
static picture_t *video_new_buffer_filter( filter_t * );
static void video_del_buffer_filter( filter_t *, picture_t * );
static int transcode_spu_new ( sout_stream_t *, sout_stream_id_t * ); static int transcode_spu_new ( sout_stream_t *, sout_stream_id_t * );
static void transcode_spu_close ( sout_stream_t *, sout_stream_id_t * ); static void transcode_spu_close ( sout_stream_t *, sout_stream_id_t * );
...@@ -290,6 +293,15 @@ struct sout_stream_sys_t ...@@ -290,6 +293,15 @@ struct sout_stream_sys_t
mtime_t i_master_drift; mtime_t i_master_drift;
}; };
struct decoder_owner_sys_t
{
picture_t *pp_pics[PICTURE_RING_SIZE];
};
struct filter_owner_sys_t
{
picture_t *pp_pics[PICTURE_RING_SIZE];
};
/***************************************************************************** /*****************************************************************************
* Open: * Open:
*****************************************************************************/ *****************************************************************************/
...@@ -448,10 +460,7 @@ static int Open( vlc_object_t *p_this ) ...@@ -448,10 +460,7 @@ static int Open( vlc_object_t *p_this )
p_sys->b_soverlay = val.b_bool; p_sys->b_soverlay = val.b_bool;
p_sys->p_filter_blend = 0; p_sys->p_filter_blend = 0;
for( i = 0; i < SUBPICTURE_RING_SIZE; i++ ) for( i = 0; i < SUBPICTURE_RING_SIZE; i++ ) p_sys->pp_subpics[i] = 0;
{
p_sys->pp_subpics[i] = 0;
}
var_Get( p_stream, SOUT_CFG_PREFIX "audio-sync", &val ); var_Get( p_stream, SOUT_CFG_PREFIX "audio-sync", &val );
p_sys->b_audio_sync = val.b_bool; p_sys->b_audio_sync = val.b_bool;
...@@ -472,6 +481,7 @@ static void Close( vlc_object_t * p_this ) ...@@ -472,6 +481,7 @@ static void Close( vlc_object_t * p_this )
{ {
sout_stream_t *p_stream = (sout_stream_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_sys_t *p_sys = p_stream->p_sys;
int i;
sout_StreamDelete( p_sys->p_out ); sout_StreamDelete( p_sys->p_out );
...@@ -523,6 +533,15 @@ static void Close( vlc_object_t * p_this ) ...@@ -523,6 +533,15 @@ static void Close( vlc_object_t * p_this )
module_Unneed( p_sys->p_filter_blend, module_Unneed( p_sys->p_filter_blend,
p_sys->p_filter_blend->p_module ); p_sys->p_filter_blend->p_module );
/* Clean-up pictures ring buffer */
for( i = 0; i < PICTURE_RING_SIZE; i++ )
{
if( p_sys->p_filter_blend->p_owner->pp_pics[i] )
video_del_buffer( VLC_OBJECT(p_sys->p_filter_blend),
p_sys->p_filter_blend->p_owner->pp_pics[i] );
}
free( p_sys->p_filter_blend->p_owner );
vlc_object_detach( p_sys->p_filter_blend ); vlc_object_detach( p_sys->p_filter_blend );
vlc_object_destroy( p_sys->p_filter_blend ); vlc_object_destroy( p_sys->p_filter_blend );
} }
...@@ -1123,6 +1142,7 @@ static void audio_del_buffer( decoder_t *p_dec, aout_buffer_t *p_buffer ) ...@@ -1123,6 +1142,7 @@ static void audio_del_buffer( decoder_t *p_dec, aout_buffer_t *p_buffer )
static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) 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_sys_t *p_sys = p_stream->p_sys;
int i;
/* /*
* Open decoder * Open decoder
...@@ -1130,10 +1150,13 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) ...@@ -1130,10 +1150,13 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
/* Initialization of decoder structures */ /* Initialization of decoder structures */
id->p_decoder->pf_decode_video = 0; id->p_decoder->pf_decode_video = 0;
id->p_decoder->pf_vout_buffer_new = video_new_buffer; id->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder;
id->p_decoder->pf_vout_buffer_del = video_del_buffer; id->p_decoder->pf_vout_buffer_del = video_del_buffer_decoder;
id->p_decoder->pf_picture_link = video_link_picture; id->p_decoder->pf_picture_link = video_link_picture_decoder;
id->p_decoder->pf_picture_unlink = video_unlink_picture; id->p_decoder->pf_picture_unlink = video_unlink_picture_decoder;
id->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) );
for( i = 0; i < PICTURE_RING_SIZE; i++ )
id->p_decoder->p_owner->pp_pics[i] = 0;
//id->p_decoder->p_cfg = p_sys->p_video_cfg; //id->p_decoder->p_cfg = p_sys->p_video_cfg;
id->p_decoder->p_module = id->p_decoder->p_module =
...@@ -1327,7 +1350,7 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream, ...@@ -1327,7 +1350,7 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream,
static void transcode_video_close( sout_stream_t *p_stream, static void transcode_video_close( sout_stream_t *p_stream,
sout_stream_id_t *id ) sout_stream_id_t *id )
{ {
int i; int i, j;
if( p_stream->p_sys->i_threads >= 1 ) if( p_stream->p_sys->i_threads >= 1 )
{ {
...@@ -1344,6 +1367,18 @@ static void transcode_video_close( sout_stream_t *p_stream, ...@@ -1344,6 +1367,18 @@ static void transcode_video_close( sout_stream_t *p_stream,
if( id->p_decoder->p_module ) if( id->p_decoder->p_module )
module_Unneed( id->p_decoder, id->p_decoder->p_module ); module_Unneed( id->p_decoder, id->p_decoder->p_module );
if( id->p_decoder->p_owner )
{
/* Clean-up pictures ring buffer */
for( i = 0; i < PICTURE_RING_SIZE; i++ )
{
if( id->p_decoder->p_owner->pp_pics[i] )
video_del_buffer( VLC_OBJECT(id->p_decoder),
id->p_decoder->p_owner->pp_pics[i] );
}
free( id->p_decoder->p_owner );
}
/* Close encoder */ /* Close encoder */
if( id->p_encoder->p_module ) if( id->p_encoder->p_module )
module_Unneed( id->p_encoder, id->p_encoder->p_module ); module_Unneed( id->p_encoder, id->p_encoder->p_module );
...@@ -1354,6 +1389,16 @@ static void transcode_video_close( sout_stream_t *p_stream, ...@@ -1354,6 +1389,16 @@ static void transcode_video_close( sout_stream_t *p_stream,
vlc_object_detach( id->pp_filter[i] ); vlc_object_detach( id->pp_filter[i] );
if( id->pp_filter[i]->p_module ) if( id->pp_filter[i]->p_module )
module_Unneed( id->pp_filter[i], id->pp_filter[i]->p_module ); module_Unneed( id->pp_filter[i], id->pp_filter[i]->p_module );
/* Clean-up pictures ring buffer */
for( j = 0; j < PICTURE_RING_SIZE; j++ )
{
if( id->pp_filter[i]->p_owner->pp_pics[j] )
video_del_buffer( VLC_OBJECT(id->pp_filter[i]),
id->pp_filter[i]->p_owner->pp_pics[j] );
}
free( id->pp_filter[i]->p_owner );
vlc_object_destroy( id->pp_filter[i] ); vlc_object_destroy( id->pp_filter[i] );
} }
} }
...@@ -1425,16 +1470,24 @@ static int transcode_video_process( sout_stream_t *p_stream, ...@@ -1425,16 +1470,24 @@ static int transcode_video_process( sout_stream_t *p_stream,
vlc_object_attach( id->pp_filter[id->i_filter], p_stream ); vlc_object_attach( id->pp_filter[id->i_filter], p_stream );
id->pp_filter[id->i_filter]->pf_vout_buffer_new = id->pp_filter[id->i_filter]->pf_vout_buffer_new =
video_new_buffer; video_new_buffer_filter;
id->pp_filter[id->i_filter]->pf_vout_buffer_del = id->pp_filter[id->i_filter]->pf_vout_buffer_del =
video_del_buffer; video_del_buffer_filter;
id->pp_filter[id->i_filter]->fmt_in = id->p_decoder->fmt_out; id->pp_filter[id->i_filter]->fmt_in = id->p_decoder->fmt_out;
id->pp_filter[id->i_filter]->fmt_out = id->p_decoder->fmt_out; id->pp_filter[id->i_filter]->fmt_out = id->p_decoder->fmt_out;
id->pp_filter[id->i_filter]->p_module = id->pp_filter[id->i_filter]->p_module =
module_Need( id->pp_filter[id->i_filter], module_Need( id->pp_filter[id->i_filter],
"video filter2", "deinterlace", 0 ); "video filter2", "deinterlace", 0 );
if( id->pp_filter[id->i_filter]->p_module ) id->i_filter++; if( id->pp_filter[id->i_filter]->p_module )
{
id->pp_filter[id->i_filter]->p_owner =
malloc( sizeof(filter_owner_sys_t) );
for( i = 0; i < PICTURE_RING_SIZE; i++ )
id->pp_filter[id->i_filter]->p_owner->pp_pics[i] = 0;
id->i_filter++;
}
else else
{ {
msg_Dbg( p_stream, "no video filter found" ); msg_Dbg( p_stream, "no video filter found" );
...@@ -1458,16 +1511,24 @@ static int transcode_video_process( sout_stream_t *p_stream, ...@@ -1458,16 +1511,24 @@ static int transcode_video_process( sout_stream_t *p_stream,
vlc_object_attach( id->pp_filter[id->i_filter], p_stream ); vlc_object_attach( id->pp_filter[id->i_filter], p_stream );
id->pp_filter[id->i_filter]->pf_vout_buffer_new = id->pp_filter[id->i_filter]->pf_vout_buffer_new =
video_new_buffer; video_new_buffer_filter;
id->pp_filter[id->i_filter]->pf_vout_buffer_del = id->pp_filter[id->i_filter]->pf_vout_buffer_del =
video_del_buffer; video_del_buffer_filter;
id->pp_filter[id->i_filter]->fmt_in = id->p_decoder->fmt_out; id->pp_filter[id->i_filter]->fmt_in = id->p_decoder->fmt_out;
id->pp_filter[id->i_filter]->fmt_out = id->p_encoder->fmt_in; id->pp_filter[id->i_filter]->fmt_out = id->p_encoder->fmt_in;
id->pp_filter[id->i_filter]->p_module = id->pp_filter[id->i_filter]->p_module =
module_Need( id->pp_filter[id->i_filter], module_Need( id->pp_filter[id->i_filter],
"video filter2", 0, 0 ); "video filter2", 0, 0 );
if( id->pp_filter[id->i_filter]->p_module ) id->i_filter++; if( id->pp_filter[id->i_filter]->p_module )
{
id->pp_filter[id->i_filter]->p_owner =
malloc( sizeof(filter_owner_sys_t) );
for( i = 0; i < PICTURE_RING_SIZE; i++ )
id->pp_filter[id->i_filter]->p_owner->pp_pics[i] = 0;
id->i_filter++;
}
else else
{ {
msg_Dbg( p_stream, "no video filter found" ); msg_Dbg( p_stream, "no video filter found" );
...@@ -1518,7 +1579,7 @@ static int transcode_video_process( sout_stream_t *p_stream, ...@@ -1518,7 +1579,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
{ {
/* We can't modify the picture, we need to duplicate it */ /* We can't modify the picture, we need to duplicate it */
picture_t *p_tmp = picture_t *p_tmp =
video_new_buffer( (decoder_t *)p_sys->p_filter_blend ); video_new_buffer_filter( p_sys->p_filter_blend );
if( p_tmp ) if( p_tmp )
{ {
int i, j; int i, j;
...@@ -1684,22 +1745,52 @@ static int EncoderThread( sout_stream_sys_t *p_sys ) ...@@ -1684,22 +1745,52 @@ static int EncoderThread( sout_stream_sys_t *p_sys )
struct picture_sys_t struct picture_sys_t
{ {
decoder_t *p_dec; vlc_object_t *p_owner;
}; };
static void video_release_buffer( picture_t *p_pic ) static void video_release_buffer( picture_t *p_pic )
{ {
if( p_pic && !p_pic->i_refcount && p_pic->pf_release && p_pic->p_sys ) if( p_pic && !p_pic->i_refcount && p_pic->pf_release && p_pic->p_sys )
{ {
video_del_buffer( p_pic->p_sys->p_dec, p_pic ); video_del_buffer_decoder( (decoder_t *)p_pic->p_sys->p_owner, p_pic );
} }
else if( p_pic && p_pic->i_refcount > 0 ) p_pic->i_refcount--; else if( p_pic && p_pic->i_refcount > 0 ) p_pic->i_refcount--;
} }
static picture_t *video_new_buffer( decoder_t *p_dec ) static picture_t *video_new_buffer( vlc_object_t *p_this, picture_t **pp_ring )
{ {
picture_t *p_pic = malloc( sizeof(picture_t) ); decoder_t *p_dec = (decoder_t *)p_this;
picture_t *p_pic;
int i;
/* Find an empty space in the picture ring buffer */
for( i = 0; i < PICTURE_RING_SIZE; i++ )
{
if( pp_ring[i] != 0 && pp_ring[i]->i_status == DESTROYED_PICTURE )
{
pp_ring[i]->i_status = RESERVED_PICTURE;
return pp_ring[i];
}
}
for( i = 0; i < PICTURE_RING_SIZE; i++ )
{
if( pp_ring[i] == 0 ) break;
}
if( i == PICTURE_RING_SIZE )
{
msg_Err( p_this, "decoder/filter is leaking pictures, "
"resetting its ring buffer" );
for( i = 0; i < PICTURE_RING_SIZE; i++ )
{
pp_ring[i]->pf_release( pp_ring[i] );
}
i = 0;
}
p_pic = malloc( sizeof(picture_t) );
p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec; p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
vout_AllocatePicture( VLC_OBJECT(p_dec), p_pic, vout_AllocatePicture( VLC_OBJECT(p_dec), p_pic,
p_dec->fmt_out.video.i_chroma, p_dec->fmt_out.video.i_chroma,
...@@ -1715,24 +1806,51 @@ static picture_t *video_new_buffer( decoder_t *p_dec ) ...@@ -1715,24 +1806,51 @@ static picture_t *video_new_buffer( decoder_t *p_dec )
p_pic->pf_release = video_release_buffer; p_pic->pf_release = video_release_buffer;
p_pic->p_sys = malloc( sizeof(picture_sys_t) ); p_pic->p_sys = malloc( sizeof(picture_sys_t) );
p_pic->p_sys->p_dec = p_dec; p_pic->p_sys->p_owner = p_this;
p_pic->i_status = RESERVED_PICTURE;
pp_ring[i] = p_pic;
return p_pic; return p_pic;
} }
static void video_del_buffer( decoder_t *p_dec, picture_t *p_pic ) static picture_t *video_new_buffer_decoder( decoder_t *p_dec )
{
return video_new_buffer( VLC_OBJECT(p_dec),
p_dec->p_owner->pp_pics );
}
static picture_t *video_new_buffer_filter( filter_t *p_filter )
{
return video_new_buffer( VLC_OBJECT(p_filter),
p_filter->p_owner->pp_pics );
}
static void video_del_buffer( vlc_object_t *p_this, picture_t *p_pic )
{ {
if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig ); if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
if( p_pic && p_pic->p_sys ) free( p_pic->p_sys ); if( p_pic && p_pic->p_sys ) free( p_pic->p_sys );
if( p_pic ) free( p_pic ); if( p_pic ) free( p_pic );
} }
static void video_link_picture( decoder_t *p_dec, picture_t *p_pic ) static void video_del_buffer_decoder( decoder_t *p_decoder, picture_t *p_pic )
{
p_pic->i_refcount = 0;
p_pic->i_status = DESTROYED_PICTURE;
}
static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic )
{
p_pic->i_refcount = 0;
p_pic->i_status = DESTROYED_PICTURE;
}
static void video_link_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
{ {
p_pic->i_refcount++; p_pic->i_refcount++;
} }
static void video_unlink_picture( decoder_t *p_dec, picture_t *p_pic ) static void video_unlink_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
{ {
video_release_buffer( p_pic ); video_release_buffer( p_pic );
} }
...@@ -1787,8 +1905,10 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id ) ...@@ -1787,8 +1905,10 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id )
return VLC_EGENERIC; return VLC_EGENERIC;
} }
} }
else else if( !p_sys->p_filter_blend )
{ {
int i;
p_sys->p_filter_blend = p_sys->p_filter_blend =
vlc_object_create( p_stream, VLC_OBJECT_FILTER ); vlc_object_create( p_stream, VLC_OBJECT_FILTER );
vlc_object_attach( p_sys->p_filter_blend, p_stream ); vlc_object_attach( p_sys->p_filter_blend, p_stream );
...@@ -1796,6 +1916,13 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id ) ...@@ -1796,6 +1916,13 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id )
VLC_FOURCC('I','4','2','0'); VLC_FOURCC('I','4','2','0');
p_sys->p_filter_blend->fmt_in.video.i_chroma = p_sys->p_filter_blend->fmt_in.video.i_chroma =
VLC_FOURCC('Y','U','V','A'); VLC_FOURCC('Y','U','V','A');
p_sys->p_filter_blend->pf_vout_buffer_new = video_new_buffer_filter;
p_sys->p_filter_blend->pf_vout_buffer_del = video_del_buffer_filter;
p_sys->p_filter_blend->p_owner = malloc( sizeof(filter_owner_sys_t) );
for( i = 0; i < PICTURE_RING_SIZE; i++ )
p_sys->p_filter_blend->p_owner->pp_pics[i] = 0;
p_sys->p_filter_blend->p_module = p_sys->p_filter_blend->p_module =
module_Need( p_sys->p_filter_blend, "video blending", 0, 0 ); module_Need( p_sys->p_filter_blend, "video blending", 0, 0 );
} }
......
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