Commit f976d6ae authored by Christophe Massiot's avatar Christophe Massiot

* ALL: converted the video output module "picture" to a stream output

   module "mosaic-bridge".
parent 0ae97f35
......@@ -986,7 +986,7 @@ if test "${SYS}" != "mingwce"; then
VLC_ADD_PLUGINS([externrun])
VLC_ADD_PLUGINS([access_fake access_filter_timeshift])
VLC_ADD_PLUGINS([gestures rc telnet hotkeys netsync showintf time marq sap shout])
VLC_ADD_PLUGINS([picture mosaic wall motiondetect clone crop])
VLC_ADD_PLUGINS([mosaic wall motiondetect clone crop])
VLC_ADD_PLUGINS([i420_yuy2 i422_yuy2 i420_ymga])
VLC_ADD_PLUGINS([aout_file linear_resampler bandlimited_resampler])
VLC_ADD_PLUGINS([float32_mixer spdif_mixer simple_channel_mixer])
......@@ -1227,7 +1227,7 @@ then
VLC_ADD_PLUGINS([packetizer_copy])
VLC_ADD_PLUGINS([stream_out_dummy stream_out_standard stream_out_es stream_out_rtp stream_out_description vod_rtsp])
VLC_ADD_PLUGINS([stream_out_duplicate stream_out_gather stream_out_display stream_out_transcode stream_out_bridge])
VLC_ADD_PLUGINS([stream_out_duplicate stream_out_gather stream_out_display stream_out_transcode stream_out_bridge stream_out_mosaic_bridge])
# VLC_ADD_PLUGINS([stream_out_transrate])
AC_DEFINE(ENABLE_SOUT, 1, Define if you want the stream output support)
......@@ -2533,7 +2533,7 @@ AC_ARG_ENABLE(speex,
if test "${enable_speex}" != "no"
then
AC_CHECK_HEADERS(speex/speex.h, [
LDFLAGS="${LDFLAGS_save} ${LDFLAGS_toolame}"
LDFLAGS="${LDFLAGS_save} ${LDFLAGS_speex}"
AC_CHECK_LIB(speex, speex_decode_int, [
VLC_ADD_PLUGINS([speex])
VLC_ADD_LDFLAGS([speex],[-lspeex]) ],
......
......@@ -11,3 +11,4 @@ SOURCES_stream_out_gather = gather.c
SOURCES_stream_out_rtp = rtp.c
SOURCES_stream_out_switcher = switcher.c
SOURCES_stream_out_bridge = bridge.c
SOURCES_stream_out_mosaic_bridge = mosaic_bridge.c
......@@ -58,7 +58,7 @@ vlc_module_begin();
set_shortname( _("Bridge"));
set_description( _("Bridge stream output"));
add_submodule();
set_section( N_("Bridge out"),NULL);
set_section( N_("Bridge out"), NULL );
set_capability( "sout stream", 50 );
add_shortcut( "bridge-out" );
/* Only usable with VLM. No category so not in gui preferences
......@@ -69,12 +69,12 @@ vlc_module_begin();
set_callbacks( OpenOut, CloseOut );
add_submodule();
set_section( N_("Bridge in"),NULL);
set_section( N_("Bridge in"), NULL );
set_capability( "sout stream", 50 );
add_shortcut( "bridge-in" );
/*set_category( CAT_SOUT );
set_subcategory( SUBCAT_SOUT_STREAM );*/
add_integer( SOUT_CFG_PREFIX_IN "delay", 100, NULL, DELAY_TEXT,
add_integer( SOUT_CFG_PREFIX_IN "delay", 0, NULL, DELAY_TEXT,
DELAY_LONGTEXT, VLC_FALSE );
add_integer( SOUT_CFG_PREFIX_IN "id-offset", 8192, NULL, ID_OFFSET_TEXT,
ID_OFFSET_LONGTEXT, VLC_FALSE );
......@@ -109,7 +109,6 @@ typedef struct bridged_es_t
block_t *p_block;
block_t **pp_last;
vlc_bool_t b_empty;
int i_id;
/* bridge in part */
sout_stream_id_t *id;
......@@ -150,9 +149,9 @@ static bridge_t *__GetBridge( vlc_object_t *p_object )
typedef struct out_sout_stream_sys_t
{
vlc_mutex_t *p_lock;
bridged_es_t *p_es;
int i_id;
vlc_bool_t b_inited;
int i_position;
} out_sout_stream_sys_t;
/*****************************************************************************
......@@ -160,7 +159,7 @@ typedef struct out_sout_stream_sys_t
*****************************************************************************/
static int OpenOut( 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;
out_sout_stream_sys_t *p_sys;
vlc_value_t val;
......@@ -182,7 +181,6 @@ static int OpenOut( vlc_object_t *p_this )
p_stream->p_sys = (sout_stream_sys_t *)p_sys;
/* update p_sout->i_out_pace_nocontrol */
p_stream->p_sout->i_out_pace_nocontrol++;
return VLC_SUCCESS;
......@@ -243,14 +241,12 @@ static sout_stream_id_t * AddOut( sout_stream_t *p_stream, es_format_t *p_fmt )
p_bridge->pp_es = realloc( p_bridge->pp_es,
(p_bridge->i_es_num + 1)
* sizeof(bridged_es_t *) );
p_sys->i_position = p_bridge->i_es_num;
p_bridge->i_es_num++;
p_bridge->pp_es[i] = malloc( sizeof(bridged_es_t) );
}
else
p_sys->i_position = i;
p_es = p_bridge->pp_es[ p_sys->i_position ];
p_sys->p_es = p_es = p_bridge->pp_es[i];
p_es->fmt = *p_fmt;
p_es->fmt.i_id = p_sys->i_id;
p_es->p_block = NULL;
......@@ -262,7 +258,7 @@ static sout_stream_id_t * AddOut( sout_stream_t *p_stream, es_format_t *p_fmt )
p_es->b_changed = VLC_TRUE;
msg_Dbg( p_stream, "bridging out input codec=%4.4s id=%d pos=%d",
(char*)&p_es->fmt.i_codec, p_es->fmt.i_id, p_sys->i_position );
(char*)&p_es->fmt.i_codec, p_es->fmt.i_id, i );
vlc_mutex_unlock( p_sys->p_lock );
......@@ -272,7 +268,6 @@ static sout_stream_id_t * AddOut( sout_stream_t *p_stream, es_format_t *p_fmt )
static int DelOut( sout_stream_t *p_stream, sout_stream_id_t *id )
{
out_sout_stream_sys_t *p_sys = (out_sout_stream_sys_t *)p_stream->p_sys;
bridge_t *p_bridge;
bridged_es_t *p_es;
if ( !p_sys->b_inited )
......@@ -282,8 +277,7 @@ static int DelOut( sout_stream_t *p_stream, sout_stream_id_t *id )
vlc_mutex_lock( p_sys->p_lock );
p_bridge = GetBridge( p_stream );
p_es = p_bridge->pp_es[ p_sys->i_position ];
p_es = p_sys->p_es;
p_es->b_empty = VLC_TRUE;
block_ChainRelease( p_es->p_block );
......@@ -299,7 +293,6 @@ static int SendOut( sout_stream_t *p_stream, sout_stream_id_t *id,
block_t *p_buffer )
{
out_sout_stream_sys_t *p_sys = (out_sout_stream_sys_t *)p_stream->p_sys;
bridge_t *p_bridge;
bridged_es_t *p_es;
if ( (out_sout_stream_sys_t *)id != p_sys )
......@@ -310,8 +303,7 @@ static int SendOut( sout_stream_t *p_stream, sout_stream_id_t *id,
vlc_mutex_lock( p_sys->p_lock );
p_bridge = GetBridge( p_stream );
p_es = p_bridge->pp_es[ p_sys->i_position ];
p_es = p_sys->p_es;
*p_es->pp_last = p_buffer;
while ( p_buffer != NULL )
{
......
/*****************************************************************************
* picture.c:
* mosaic_bridge.c:
*****************************************************************************
* Copyright (C) 2004-2005 VideoLAN
* $Id$
......@@ -30,32 +30,33 @@
#include <string.h> /* strerror() */
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/sout.h>
#include <vlc/decoder.h>
#include "vlc_image.h"
#include "picture.h"
#include "../video_filter/mosaic.h"
/*****************************************************************************
* Local structures
*****************************************************************************/
struct vout_sys_t
struct sout_stream_sys_t
{
picture_vout_t *p_picture_vout;
bridged_es_t *p_es;
vlc_mutex_t *p_lock;
int i_picture_pos; /* picture position in p_picture_vout */
image_handler_t *p_image; /* filters for resizing */
#ifdef IMAGE_2PASSES
image_handler_t *p_image2;
#endif
decoder_t *p_decoder;
image_handler_t *p_image; /* filter for resizing */
int i_height, i_width;
mtime_t i_last_pic;
char *psz_id;
vlc_bool_t b_inited;
};
/* Delay after which the picture is blanked out if there hasn't been any
* new picture. */
#define BLANK_DELAY I64C(1000000)
#define PICTURE_RING_SIZE 64
struct decoder_owner_sys_t
{
picture_t *pp_pics[PICTURE_RING_SIZE];
};
typedef void (* pf_release_t)( picture_t * );
static void ReleasePicture( picture_t *p_pic )
......@@ -83,10 +84,14 @@ static void ReleasePicture( picture_t *p_pic )
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static int Init ( vout_thread_t * );
static void End ( vout_thread_t * );
static int Manage ( vout_thread_t * );
static void Display ( vout_thread_t *, picture_t * );
static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
static int Del ( sout_stream_t *, sout_stream_id_t * );
static int Send( sout_stream_t *, sout_stream_id_t *, block_t * );
static void video_del_buffer( decoder_t *, picture_t * );
static picture_t *video_new_buffer( decoder_t * );
static void video_link_picture_decoder( decoder_t *, picture_t * );
static void video_unlink_picture_decoder( decoder_t *, picture_t * );
/*****************************************************************************
* Module descriptor
......@@ -102,226 +107,231 @@ static void Display ( vout_thread_t *, picture_t * );
#define HEIGHT_LONGTEXT N_( \
"Allows you to specify the output video height." )
vlc_module_begin();
set_shortname( _( "Picture" ) );
set_description(_("VLC internal picture video output") );
set_capability( "video output", 0 );
#define SOUT_CFG_PREFIX "sout-mosaic-bridge-"
add_string( "picture-id", "Id", NULL, ID_TEXT, ID_LONGTEXT, VLC_FALSE );
add_integer( "picture-width", 0, NULL, WIDTH_TEXT,
vlc_module_begin();
set_shortname( _( "Mosaic bridge" ) );
set_description(_("Mosaic bridge stream output") );
set_capability( "sout stream", 0 );
add_shortcut( "mosaic-bridge" );
add_string( SOUT_CFG_PREFIX "id", "Id", NULL, ID_TEXT, ID_LONGTEXT,
VLC_FALSE );
add_integer( SOUT_CFG_PREFIX "width", 0, NULL, WIDTH_TEXT,
WIDTH_LONGTEXT, VLC_TRUE );
add_integer( "picture-height", 0, NULL, HEIGHT_TEXT,
add_integer( SOUT_CFG_PREFIX "height", 0, NULL, HEIGHT_TEXT,
HEIGHT_LONGTEXT, VLC_TRUE );
set_callbacks( Open, Close );
var_Create( p_module->p_libvlc, "picture-lock", VLC_VAR_MUTEX );
var_Create( p_module->p_libvlc, "mosaic-lock", VLC_VAR_MUTEX );
vlc_module_end();
static const char *ppsz_sout_options[] = {
"id", "width", "height", NULL
};
/*****************************************************************************
* Open : allocate video thread output method
* Open
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
vout_thread_t *p_vout = (vout_thread_t *)p_this;
vout_sys_t *p_sys;
libvlc_t *p_libvlc = p_vout->p_libvlc;
picture_vout_t *p_picture_vout = NULL;
picture_vout_e_t *p_pic;
vlc_value_t val, lockval;
p_sys = p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
if( p_sys == NULL )
{
msg_Err( p_vout, "out of memory" );
return VLC_ENOMEM;
}
sout_stream_t *p_stream = (sout_stream_t *)p_this;
sout_stream_sys_t *p_sys;
libvlc_t *p_libvlc = p_this->p_libvlc;
vlc_value_t val;
var_Get( p_libvlc, "picture-lock", &lockval );
p_sys->p_lock = lockval.p_address;
vlc_mutex_lock( p_sys->p_lock );
sout_CfgParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
p_stream->p_cfg );
p_sys->i_picture_pos = -1;
if( var_Get( p_libvlc, "p_picture_vout", &val ) != VLC_SUCCESS )
{
p_picture_vout = malloc( sizeof( struct picture_vout_t ) );
if( p_picture_vout == NULL )
{
msg_Err( p_vout, "out of memory" );
return VLC_ENOMEM;
}
p_sys = malloc( sizeof( sout_stream_sys_t ) );
p_stream->p_sys = p_sys;
p_sys->b_inited = VLC_FALSE;
var_Create( p_libvlc, "p_picture_vout", VLC_VAR_ADDRESS );
val.p_address = p_picture_vout;
var_Set( p_libvlc, "p_picture_vout", val );
var_Get( p_libvlc, "mosaic-lock", &val );
p_sys->p_lock = val.p_address;
p_picture_vout->i_picture_num = 0;
p_picture_vout->p_pic = NULL;
}
else
{
int i;
p_picture_vout = val.p_address;
for ( i = 0; i < p_picture_vout->i_picture_num; i++ )
{
if ( p_picture_vout->p_pic[i].i_status == PICTURE_VOUT_E_AVAILABLE )
break;
}
if ( i != p_picture_vout->i_picture_num )
p_sys->i_picture_pos = i;
}
p_sys->p_picture_vout = p_picture_vout;
if ( p_sys->i_picture_pos == -1 )
{
p_picture_vout->p_pic = realloc( p_picture_vout->p_pic,
(p_picture_vout->i_picture_num + 1)
* sizeof(picture_vout_e_t) );
p_sys->i_picture_pos = p_picture_vout->i_picture_num;
p_picture_vout->i_picture_num++;
}
p_pic = &p_picture_vout->p_pic[p_sys->i_picture_pos];
p_pic->p_picture = NULL;
p_pic->i_status = PICTURE_VOUT_E_OCCUPIED;
var_Get( p_stream, SOUT_CFG_PREFIX "id", &val );
p_sys->psz_id = val.psz_string;
var_Create( p_vout, "picture-id", VLC_VAR_STRING );
var_Change( p_vout, "picture-id", VLC_VAR_INHERITVALUE, &val, NULL );
p_pic->psz_id = val.psz_string;
vlc_mutex_unlock( p_sys->p_lock );
var_Create( p_vout, "picture-height", VLC_VAR_INTEGER );
var_Change( p_vout, "picture-height", VLC_VAR_INHERITVALUE, &val, NULL );
var_Get( p_stream, SOUT_CFG_PREFIX "height", &val );
p_sys->i_height = val.i_int;
var_Create( p_vout, "picture-width", VLC_VAR_INTEGER );
var_Change( p_vout, "picture-width", VLC_VAR_INHERITVALUE, &val, NULL );
var_Get( p_stream, SOUT_CFG_PREFIX "width", &val );
p_sys->i_width = val.i_int;
if ( p_sys->i_height || p_sys->i_width )
{
p_sys->p_image = image_HandlerCreate( p_vout );
#ifdef IMAGE_2PASSES
p_sys->p_image2 = image_HandlerCreate( p_vout );
#endif
p_sys->p_image = image_HandlerCreate( p_stream );
}
p_sys->i_last_pic = 0;
p_stream->pf_add = Add;
p_stream->pf_del = Del;
p_stream->pf_send = Send;
p_vout->pf_init = Init;
p_vout->pf_end = End;
p_vout->pf_manage = Manage;
p_vout->pf_render = NULL;
p_vout->pf_display = Display;
p_stream->p_sout->i_out_pace_nocontrol++;
return VLC_SUCCESS;
}
/*****************************************************************************
* Init
* Close
*****************************************************************************/
static int Init( vout_thread_t *p_vout )
static void Close( vlc_object_t * p_this )
{
picture_t *p_pic;
int i_index;
sout_stream_t *p_stream = (sout_stream_t*)p_this;
sout_stream_sys_t *p_sys = p_stream->p_sys;
p_stream->p_sout->i_out_pace_nocontrol--;
I_OUTPUTPICTURES = 0;
if ( p_sys->psz_id )
free( p_sys->psz_id );
p_vout->output.i_chroma = p_vout->render.i_chroma;
p_vout->output.i_width = p_vout->render.i_width;
p_vout->output.i_height = p_vout->render.i_height;
p_vout->output.i_aspect = p_vout->render.i_aspect;
free( p_sys );
}
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;
bridge_t *p_bridge;
bridged_es_t *p_es;
int i;
while( VLC_TRUE )
if ( p_sys->b_inited )
{
p_pic = NULL;
return NULL;
}
for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
{
if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
{
p_pic = p_vout->p_picture + i_index;
break;
}
}
/* Create decoder object */
p_sys->p_decoder = vlc_object_create( p_stream, VLC_OBJECT_DECODER );
vlc_object_attach( p_sys->p_decoder, p_stream );
p_sys->p_decoder->p_module = NULL;
p_sys->p_decoder->fmt_in = *p_fmt;
p_sys->p_decoder->b_pace_control = VLC_FALSE;
p_sys->p_decoder->fmt_out = p_sys->p_decoder->fmt_in;
p_sys->p_decoder->fmt_out.i_extra = 0;
p_sys->p_decoder->fmt_out.p_extra = 0;
p_sys->p_decoder->pf_decode_video = 0;
p_sys->p_decoder->pf_vout_buffer_new = video_new_buffer;
p_sys->p_decoder->pf_vout_buffer_del = video_del_buffer;
p_sys->p_decoder->pf_picture_link = video_link_picture_decoder;
p_sys->p_decoder->pf_picture_unlink = video_unlink_picture_decoder;
p_sys->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) );
for( i = 0; i < PICTURE_RING_SIZE; i++ )
p_sys->p_decoder->p_owner->pp_pics[i] = 0;
//p_sys->p_decoder->p_cfg = p_sys->p_video_cfg;
p_sys->p_decoder->p_module =
module_Need( p_sys->p_decoder, "decoder", "$codec", 0 );
if( !p_sys->p_decoder->p_module )
{
msg_Err( p_stream, "cannot find decoder" );
vlc_object_detach( p_sys->p_decoder );
vlc_object_destroy( p_sys->p_decoder );
return NULL;
}
if( p_pic == NULL )
{
return VLC_SUCCESS;
}
p_sys->b_inited = VLC_TRUE;
vlc_mutex_lock( p_sys->p_lock );
vout_AllocatePicture( VLC_OBJECT(p_vout), p_pic,
p_vout->output.i_chroma,
p_vout->output.i_width, p_vout->output.i_height,
p_vout->output.i_aspect );
p_bridge = GetBridge( p_stream );
if ( p_bridge == NULL )
{
libvlc_t *p_libvlc = p_stream->p_libvlc;
vlc_value_t val;
if( p_pic->i_planes == 0 )
{
return VLC_EGENERIC;
}
p_bridge = malloc( sizeof( bridge_t ) );
p_pic->i_status = DESTROYED_PICTURE;
p_pic->i_type = DIRECT_PICTURE;
var_Create( p_libvlc, "mosaic-struct", VLC_VAR_ADDRESS );
val.p_address = p_bridge;
var_Set( p_libvlc, "mosaic-struct", val );
PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
p_bridge->i_es_num = 0;
p_bridge->pp_es = NULL;
}
I_OUTPUTPICTURES++;
for ( i = 0; i < p_bridge->i_es_num; i++ )
{
if ( p_bridge->pp_es[i]->b_empty )
break;
}
//return VLC_SUCCESS;
if ( i == p_bridge->i_es_num )
{
p_bridge->pp_es = realloc( p_bridge->pp_es,
(p_bridge->i_es_num + 1)
* sizeof(bridged_es_t *) );
p_bridge->i_es_num++;
p_bridge->pp_es[i] = malloc( sizeof(bridged_es_t) );
}
}
p_sys->p_es = p_es = p_bridge->pp_es[i];
/*****************************************************************************
* End
*****************************************************************************/
static void End( vout_thread_t *p_vout )
{
return;
//p_es->fmt = *p_fmt;
p_es->psz_id = p_sys->psz_id;
p_es->p_picture = NULL;
p_es->pp_last = &p_es->p_picture;
p_es->b_empty = VLC_FALSE;
vlc_mutex_unlock( p_sys->p_lock );
msg_Dbg( p_stream, "mosaic bridge id=%s pos=%d", p_es->psz_id, i );
return (sout_stream_id_t *)p_sys;
}
/*****************************************************************************
* Close
*****************************************************************************/
static void Close( vlc_object_t *p_this )
static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
{
vout_thread_t *p_vout = (vout_thread_t *)p_this;
vout_sys_t *p_sys = p_vout->p_sys;
picture_vout_t *p_picture_vout = p_sys->p_picture_vout;
picture_vout_e_t *p_pic;
vlc_bool_t b_last_picture = VLC_TRUE;
sout_stream_sys_t *p_sys = p_stream->p_sys;
bridge_t *p_bridge;
bridged_es_t *p_es;
vlc_bool_t b_last_es = VLC_TRUE;
int i;
if ( !p_sys->b_inited )
{
return VLC_SUCCESS;
}
if ( p_sys->p_decoder )
{
if( p_sys->p_decoder->p_module )
module_Unneed( p_sys->p_decoder, p_sys->p_decoder->p_module );
vlc_object_detach( p_sys->p_decoder );
vlc_object_destroy( p_sys->p_decoder );
}
vlc_mutex_lock( p_sys->p_lock );
p_pic = &p_picture_vout->p_pic[p_sys->i_picture_pos];
if( p_pic->p_picture )
p_bridge = GetBridge( p_stream );
p_es = p_sys->p_es;
p_es->b_empty = VLC_TRUE;
while ( p_es->p_picture )
{
p_pic->p_picture->pf_release( p_pic->p_picture );
p_pic->p_picture = NULL;
picture_t *p_next = p_es->p_picture->p_next;
p_es->p_picture->pf_release( p_es->p_picture );
p_es->p_picture = p_next;
}
p_pic->i_status = PICTURE_VOUT_E_AVAILABLE;
if( p_pic->psz_id )
free( p_pic->psz_id );
for( i = 0; i < p_picture_vout->i_picture_num; i ++)
for ( i = 0; i < p_bridge->i_es_num; i++ )
{
if( p_picture_vout->p_pic[i].i_status == PICTURE_VOUT_E_OCCUPIED )
if ( !p_bridge->pp_es[i]->b_empty )
{
b_last_picture = VLC_FALSE;
b_last_es = VLC_FALSE;
break;
}
}
if( b_last_picture )
if ( b_last_es )
{
free( p_picture_vout->p_pic );
free( p_picture_vout );
var_Destroy( p_this->p_libvlc, "p_picture_vout" );
libvlc_t *p_libvlc = p_stream->p_libvlc;
for ( i = 0; i < p_bridge->i_es_num; i++ )
free( p_bridge->pp_es[i] );
free( p_bridge->pp_es );
free( p_bridge );
var_Destroy( p_libvlc, "mosaic-struct" );
}
vlc_mutex_unlock( p_sys->p_lock );
......@@ -329,160 +339,174 @@ static void Close( vlc_object_t *p_this )
if ( p_sys->i_height || p_sys->i_width )
{
image_HandlerDelete( p_sys->p_image );
#ifdef IMAGE_2PASSES
image_HandlerDelete( p_sys->p_image2 );
#endif
}
free( p_sys );
p_sys->b_inited = VLC_FALSE;
return VLC_SUCCESS;
}
/*****************************************************************************
* PushPicture : push a picture in the p_picture_vout structure
* PushPicture : push a picture in the mosaic-struct structure
*****************************************************************************/
static void PushPicture( vout_thread_t *p_vout, picture_t *p_picture )
static void PushPicture( sout_stream_t *p_stream, picture_t *p_picture )
{
vout_sys_t *p_sys = p_vout->p_sys;
picture_vout_t *p_picture_vout = p_sys->p_picture_vout;
picture_vout_e_t *p_pic;
sout_stream_sys_t *p_sys = p_stream->p_sys;
bridged_es_t *p_es = p_sys->p_es;
vlc_mutex_lock( p_sys->p_lock );
p_pic = &p_picture_vout->p_pic[p_sys->i_picture_pos];
if( p_pic->p_picture != NULL )
{
p_pic->p_picture->pf_release( p_pic->p_picture );
}
p_pic->p_picture = p_picture;
*p_es->pp_last = p_picture;
p_picture->p_next = NULL;
p_es->pp_last = &p_picture->p_next;
vlc_mutex_unlock( p_sys->p_lock );
}
/*****************************************************************************
* Manage
*****************************************************************************/
static int Manage( vout_thread_t *p_vout )
static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
block_t *p_buffer )
{
vout_sys_t *p_sys = p_vout->p_sys;
sout_stream_sys_t *p_sys = p_stream->p_sys;
picture_t *p_pic;
if ( (sout_stream_sys_t *)id != p_sys )
{
block_ChainRelease( p_buffer );
return VLC_SUCCESS;
}
if ( mdate() - p_sys->i_last_pic > BLANK_DELAY )
while ( (p_pic = p_sys->p_decoder->pf_decode_video( p_sys->p_decoder,
&p_buffer )) )
{
/* Display black */
#if 0
picture_t *p_new_pic = (picture_t*)malloc( sizeof(picture_t) );
int i;
picture_t *p_new_pic;
if ( p_sys->i_height || p_sys->i_width )
{
vout_AllocatePicture( p_vout, p_new_pic,
VLC_FOURCC('Y','U','V','A'),
p_sys->i_width, p_sys->i_height,
p_vout->render.i_aspect );
video_format_t fmt_out = {0}, fmt_in = {0};
fmt_in = p_sys->p_decoder->fmt_out.video;
fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
fmt_out.i_width = p_sys->i_width;
fmt_out.i_height = p_sys->i_height;
fmt_out.i_visible_width = fmt_out.i_width;
fmt_out.i_visible_height = fmt_out.i_height;
p_new_pic = image_Convert( p_sys->p_image,
p_pic, &fmt_in, &fmt_out );
if ( p_new_pic == NULL )
{
msg_Err( p_stream, "image conversion failed" );
continue;
}
}
else
{
vout_AllocatePicture( p_vout, p_new_pic, p_vout->render.i_chroma,
p_vout->render.i_width,
p_vout->render.i_height,
p_vout->render.i_aspect );
p_new_pic = (picture_t*)malloc( sizeof(picture_t) );
vout_AllocatePicture( p_stream, p_new_pic, p_pic->format.i_chroma,
p_pic->format.i_width, p_pic->format.i_height,
p_sys->p_decoder->fmt_out.video.i_aspect );
vout_CopyPicture( p_stream, p_new_pic, p_pic );
}
p_pic->pf_release( p_pic );
p_new_pic->i_refcount++;
p_new_pic->i_refcount = 1;
p_new_pic->i_status = DESTROYED_PICTURE;
p_new_pic->i_type = DIRECT_PICTURE;
p_new_pic->p_sys = (picture_sys_t *)p_new_pic->pf_release;
p_new_pic->pf_release = ReleasePicture;
p_new_pic->date = p_pic->date;
for ( i = 0; i < p_pic->i_planes; i++ )
{
/* This assumes planar YUV format */
p_vout->p_vlc->pf_memset( p_pic->p[i].p_pixels, i ? 0x80 : 0,
p_pic->p[i].i_lines
* p_pic->p[i].i_pitch );
}
PushPicture( p_vout, p_new_pic );
#else
PushPicture( p_vout, NULL );
#endif
p_sys->i_last_pic = INT64_MAX;
PushPicture( p_stream, p_new_pic );
}
return VLC_SUCCESS;
}
/*****************************************************************************
* Display
*****************************************************************************/
static void Display( vout_thread_t *p_vout, picture_t *p_pic )
struct picture_sys_t
{
vout_sys_t *p_sys = p_vout->p_sys;
picture_t *p_new_pic;
vlc_object_t *p_owner;
};
if ( p_sys->i_height || p_sys->i_width )
static void video_release_buffer( picture_t *p_pic )
{
if( p_pic && !p_pic->i_refcount && p_pic->pf_release && p_pic->p_sys )
{
video_format_t fmt_out = {0}, fmt_in = {0};
#ifdef IMAGE_2PASSES
vide_format_t fmt_middle = {0};
picture_t *p_new_pic2;
#endif
fmt_in = p_vout->fmt_in;
#ifdef IMAGE_2PASSES
fmt_middle.i_chroma = p_vout->render.i_chroma;
fmt_middle.i_width = p_vout->p_sys->i_width;
fmt_middle.i_height = p_vout->p_sys->i_height;
fmt_middle.i_visible_width = fmt_middle.i_width;
fmt_middle.i_visible_height = fmt_middle.i_height;
p_new_pic2 = image_Convert( p_vout->p_sys->p_image2,
p_pic, &fmt_in, &fmt_middle );
if ( p_new_pic2 == NULL )
video_del_buffer( (decoder_t *)p_pic->p_sys->p_owner, p_pic );
}
else if( p_pic && p_pic->i_refcount > 0 ) p_pic->i_refcount--;
}
static picture_t *video_new_buffer( decoder_t *p_dec )
{
picture_t **pp_ring = p_dec->p_owner->pp_pics;
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 )
{
msg_Err( p_vout, "image resizing failed %dx%d->%dx%d %4.4s",
p_vout->render.i_width, p_vout->render.i_height,
fmt_middle.i_width, fmt_middle.i_height,
(char *)&p_vout->render.i_chroma);
return;
pp_ring[i]->i_status = RESERVED_PICTURE;
return pp_ring[i];
}
#endif
fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
fmt_out.i_width = p_sys->i_width;
fmt_out.i_height = p_sys->i_height;
fmt_out.i_visible_width = fmt_out.i_width;
fmt_out.i_visible_height = fmt_out.i_height;
#ifdef IMAGE_2PASSES
p_new_pic = image_Convert( p_vout->p_sys->p_image,
p_new_pic2, &fmt_middle, &fmt_out );
p_new_pic2->pf_release( p_new_pic2 );
#else
p_new_pic = image_Convert( p_vout->p_sys->p_image,
p_pic, &fmt_in, &fmt_out );
#endif
if ( p_new_pic == NULL )
}
for( i = 0; i < PICTURE_RING_SIZE; i++ )
{
if( pp_ring[i] == 0 ) break;
}
if( i == PICTURE_RING_SIZE )
{
msg_Err( p_dec, "decoder/filter is leaking pictures, "
"resetting its ring buffer" );
for( i = 0; i < PICTURE_RING_SIZE; i++ )
{
msg_Err( p_vout, "image conversion failed" );
return;
pp_ring[i]->pf_release( pp_ring[i] );
}
i = 0;
}
else
{
p_new_pic = (picture_t*)malloc( sizeof(picture_t) );
vout_AllocatePicture( p_vout, p_new_pic, p_pic->format.i_chroma,
p_pic->format.i_width, p_pic->format.i_height,
p_vout->render.i_aspect );
vout_CopyPicture( p_vout, p_new_pic, p_pic );
p_pic = malloc( sizeof(picture_t) );
p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
vout_AllocatePicture( VLC_OBJECT(p_dec), p_pic,
p_dec->fmt_out.video.i_chroma,
p_dec->fmt_out.video.i_width,
p_dec->fmt_out.video.i_height,
p_dec->fmt_out.video.i_aspect );
if( !p_pic->i_planes )
{
free( p_pic );
return 0;
}
p_new_pic->i_refcount = 1;
p_new_pic->i_status = DESTROYED_PICTURE;
p_new_pic->i_type = DIRECT_PICTURE;
p_new_pic->p_sys = (picture_sys_t *)p_new_pic->pf_release;
p_new_pic->pf_release = ReleasePicture;
p_pic->pf_release = video_release_buffer;
p_pic->p_sys = malloc( sizeof(picture_sys_t) );
p_pic->p_sys->p_owner = VLC_OBJECT(p_dec);
p_pic->i_status = RESERVED_PICTURE;
PushPicture( p_vout, p_new_pic );
p_sys->i_last_pic = p_pic->date;
pp_ring[i] = p_pic;
return p_pic;
}
static void video_del_buffer( decoder_t *p_this, 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++;
}
static void video_unlink_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
{
video_release_buffer( p_pic );
}
SOURCES_mosaic = mosaic.c
SOURCES_mosaic = mosaic.c mosaic.h
SOURCES_transform = transform.c
SOURCES_invert = invert.c
SOURCES_adjust = adjust.c
......
......@@ -39,7 +39,9 @@
#include "vlc_filter.h"
#include "vlc_image.h"
#include "../video_output/picture.h"
#include "mosaic.h"
#define BLANK_DELAY I64C(1000000)
/*****************************************************************************
* Local prototypes
......@@ -58,11 +60,9 @@ static int MosaicCallback( vlc_object_t *, char const *, vlc_value_t,
struct filter_sys_t
{
vlc_mutex_t lock;
vlc_mutex_t *p_lock;
image_handler_t *p_image;
#ifdef IMAGE_2PASSES
image_handler_t *p_image2;
#endif
picture_t *p_pic;
int i_position; /* mosaic positioning method */
......@@ -108,7 +108,7 @@ struct filter_sys_t
#define DELAY_TEXT N_("Delay")
#define DELAY_LONGTEXT N_("Pictures coming from the picture video outputs " \
"will be delayed accordingly (in milliseconds, >= 100 ms). For high " \
"will be delayed accordingly (in milliseconds). For high " \
"values you will need to raise file-caching and others.")
static int pi_pos_values[] = { 0, 1 };
......@@ -145,8 +145,10 @@ vlc_module_begin();
add_bool( "mosaic-keep-picture", 0, NULL, KEEP_TEXT, KEEP_TEXT, VLC_FALSE );
add_string( "mosaic-order", "", NULL, ORDER_TEXT, ORDER_TEXT, VLC_FALSE );
add_integer( "mosaic-delay", 100, NULL, DELAY_TEXT, DELAY_LONGTEXT,
add_integer( "mosaic-delay", 0, NULL, DELAY_TEXT, DELAY_LONGTEXT,
VLC_FALSE );
var_Create( p_module->p_libvlc, "mosaic-lock", VLC_VAR_MUTEX );
vlc_module_end();
......@@ -160,6 +162,7 @@ static int CreateFilter( vlc_object_t *p_this )
libvlc_t *p_libvlc = p_filter->p_libvlc;
char *psz_order;
int i_index;
vlc_value_t val;
/* Allocate structure */
p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
......@@ -175,6 +178,9 @@ static int CreateFilter( vlc_object_t *p_this )
vlc_mutex_init( p_filter, &p_sys->lock );
vlc_mutex_lock( &p_sys->lock );
var_Get( p_libvlc, "mosaic-lock", &val );
p_sys->p_lock = val.p_address;
#define GET_VAR( name, min, max ) \
p_sys->i_##name = __MIN( max, __MAX( min, \
var_CreateGetInteger( p_filter, "mosaic-" #name ) ) ); \
......@@ -216,9 +222,6 @@ static int CreateFilter( vlc_object_t *p_this )
if ( !p_sys->b_keep )
{
p_sys->p_image = image_HandlerCreate( p_filter );
#ifdef IMAGE_2PASSES
p_sys->p_image2 = image_HandlerCreate( p_filter );
#endif
}
p_sys->i_order_length = 0;
......@@ -244,8 +247,6 @@ static int CreateFilter( vlc_object_t *p_this )
vlc_mutex_unlock( &p_sys->lock );
vlc_thread_set_priority( p_filter, VLC_THREAD_PRIORITY_OUTPUT );
return VLC_SUCCESS;
}
......@@ -264,9 +265,6 @@ static void DestroyFilter( vlc_object_t *p_this )
if( !p_sys->b_keep )
{
image_HandlerDelete( p_sys->p_image );
#ifdef IMAGE_2PASSES
image_HandlerDelete( p_sys->p_image2 );
#endif
}
if( p_sys->i_order_length )
......@@ -313,7 +311,7 @@ static void MosaicReleasePicture( picture_t *p_picture )
static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
{
filter_sys_t *p_sys = p_filter->p_sys;
libvlc_t *p_libvlc = p_filter->p_libvlc;
bridge_t *p_bridge;
subpicture_t *p_spu;
......@@ -323,26 +321,6 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
subpicture_region_t *p_region;
subpicture_region_t *p_region_prev = NULL;
picture_vout_t *p_picture_vout;
vlc_value_t val, lockval;
/* Wait for the specified date. This is to avoid running too fast and
* take twice the same pictures. */
mwait( date - p_sys->i_delay );
if ( var_Get( p_libvlc, "picture-lock", &lockval ) )
return NULL;
vlc_mutex_lock( lockval.p_address );
if( var_Get( p_libvlc, "p_picture_vout", &val ) )
{
vlc_mutex_unlock( lockval.p_address );
return NULL;
}
p_picture_vout = val.p_address;
/* Allocate the subpicture internal data. */
p_spu = p_filter->pf_sub_buffer_new( p_filter );
if( !p_spu )
......@@ -360,28 +338,33 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
p_spu->b_absolute = VLC_FALSE;
vlc_mutex_lock( &p_sys->lock );
vlc_mutex_lock( p_sys->p_lock );
p_bridge = GetBridge( p_filter );
if ( p_bridge == NULL )
{
vlc_mutex_unlock( p_sys->p_lock );
vlc_mutex_unlock( &p_sys->lock );
return p_spu;
}
if( p_sys->i_position == 0 ) /* use automatic positioning */
if ( p_sys->i_position == 0 ) /* use automatic positioning */
{
int i_numpics = p_sys->i_order_length; /* keep slots and all */
for( i_index = 0;
i_index < p_picture_vout->i_picture_num;
i_index++ )
for ( i_index = 0; i_index < p_bridge->i_es_num; i_index++ )
{
if( p_picture_vout->p_pic[i_index].i_status
== PICTURE_VOUT_E_OCCUPIED )
bridged_es_t *p_es = p_bridge->pp_es[i_index];
if ( !p_es->b_empty )
{
i_numpics ++;
if( p_sys->i_order_length
&& p_picture_vout->p_pic[i_index].psz_id != 0 )
if( p_sys->i_order_length && p_es->psz_id != 0 )
{
/* We also want to leave slots for images given in
* mosaic-order that are not available in p_vout_picture */
int i;
for( i = 0; i < p_sys->i_order_length ; i++ )
{
if( !strcmp( p_sys->ppsz_order[i],
p_picture_vout->p_pic[i_index].psz_id ) )
if( !strcmp( p_sys->ppsz_order[i], p_es->psz_id ) )
{
i_numpics--;
break;
......@@ -399,50 +382,66 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
i_real_index = 0;
for( i_index = 0; i_index < p_picture_vout->i_picture_num; i_index++ )
for ( i_index = 0; i_index < p_bridge->i_es_num; i_index++ )
{
picture_vout_e_t *p_pic = &p_picture_vout->p_pic[i_index];
bridged_es_t *p_es = p_bridge->pp_es[i_index];
video_format_t fmt_in = {0}, fmt_out = {0};
picture_t *p_converted;
#ifdef IMAGE_2PASSES
video_format_t fmt_middle = {0};
picture_t *p_middle;
#endif
if( p_pic->i_status == PICTURE_VOUT_E_AVAILABLE
|| p_pic->p_picture == NULL )
{
if ( p_es->b_empty || p_es->p_picture == NULL )
continue;
if ( p_es->p_picture->date + p_sys->i_delay < date )
{
if ( p_es->p_picture->p_next != NULL )
{
picture_t *p_next = p_es->p_picture->p_next;
p_es->p_picture->pf_release( p_es->p_picture );
p_es->p_picture = p_next;
}
else if ( p_es->p_picture->date + p_sys->i_delay + BLANK_DELAY <
date )
{
/* Display blank */
p_es->p_picture->pf_release( p_es->p_picture );
p_es->p_picture = NULL;
p_es->pp_last = &p_es->p_picture;
continue;
}
else
msg_Dbg( p_filter, "too late picture %lld for %s",
date - p_es->p_picture->date - p_sys->i_delay,
p_es->psz_id );
}
if( p_sys->i_order_length == 0 )
if ( p_sys->i_order_length == 0 )
{
i_real_index++;
}
else
{
int i;
for( i = 0; i <= p_sys->i_order_length; i++ )
for ( i = 0; i <= p_sys->i_order_length; i++ )
{
if( i == p_sys->i_order_length ) break;
if( strcmp( p_pic->psz_id, p_sys->ppsz_order[i] ) == 0 )
if ( i == p_sys->i_order_length ) break;
if ( strcmp( p_es->psz_id, p_sys->ppsz_order[i] ) == 0 )
{
i_real_index = i;
break;
}
}
if( i == p_sys->i_order_length )
if ( i == p_sys->i_order_length )
i_real_index = ++i_greatest_real_index_used;
}
i_row = ( i_real_index / p_sys->i_cols ) % p_sys->i_rows;
i_col = i_real_index % p_sys->i_cols ;
if( !p_sys->b_keep )
if ( !p_sys->b_keep )
{
/* Convert the images */
fmt_in.i_chroma = p_pic->p_picture->format.i_chroma;
fmt_in.i_height = p_pic->p_picture->format.i_height;
fmt_in.i_width = p_pic->p_picture->format.i_width;
fmt_in.i_chroma = p_es->p_picture->format.i_chroma;
fmt_in.i_height = p_es->p_picture->format.i_height;
fmt_in.i_width = p_es->p_picture->format.i_width;
fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
fmt_out.i_width = fmt_in.i_width *
......@@ -457,42 +456,19 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
> (float)fmt_in.i_width / (float)fmt_in.i_height )
{
fmt_out.i_width = ( fmt_out.i_height * fmt_in.i_width )
/ fmt_in.i_height ;
/ fmt_in.i_height;
}
else
{
fmt_out.i_height = ( fmt_out.i_width * fmt_in.i_height )
/ fmt_in.i_width ;
/ fmt_in.i_width;
}
}
fmt_out.i_visible_width = fmt_out.i_width;
fmt_out.i_visible_height = fmt_out.i_height;
#ifdef IMAGE_2PASSES
fmt_middle.i_chroma = fmt_in.i_chroma;
fmt_middle.i_visible_width = fmt_middle.i_width = fmt_out.i_width;
fmt_middle.i_visible_height = fmt_middle.i_height = fmt_out.i_height;
p_middle = image_Convert( p_sys->p_image2, p_pic->p_picture,
&fmt_in, &fmt_middle );
if( !p_middle )
{
msg_Warn( p_filter, "image resizing failed" );
continue;
}
p_converted = image_Convert( p_sys->p_image, p_middle,
&fmt_middle, &fmt_out );
p_middle->pf_release( p_middle );
if( !p_converted )
{
msg_Warn( p_filter, "image chroma conversion failed" );
continue;
}
#else
p_converted = image_Convert( p_sys->p_image, p_pic->p_picture,
p_converted = image_Convert( p_sys->p_image, p_es->p_picture,
&fmt_in, &fmt_out );
if( !p_converted )
{
......@@ -500,11 +476,10 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
"image resizing and chroma conversion failed" );
continue;
}
#endif
}
else
{
p_converted = p_pic->p_picture;
p_converted = p_es->p_picture;
p_converted->i_refcount++;
fmt_in.i_width = fmt_out.i_width = p_converted->format.i_width;
fmt_in.i_height = fmt_out.i_height = p_converted->format.i_height;
......@@ -520,8 +495,8 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
msg_Err( p_filter, "cannot allocate SPU region" );
p_filter->pf_sub_buffer_del( p_filter, p_spu );
vlc_mutex_unlock( &p_sys->lock );
vlc_mutex_unlock( lockval.p_address );
return NULL;
vlc_mutex_unlock( p_sys->p_lock );
return p_spu;
}
/* HACK ALERT : let's fix the pointers to avoid picture duplication.
......@@ -578,8 +553,8 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
p_region_prev = p_region;
}
vlc_mutex_unlock( p_sys->p_lock );
vlc_mutex_unlock( &p_sys->lock );
vlc_mutex_unlock( lockval.p_address );
return p_spu;
}
......
/*****************************************************************************
* picture.h:
* mosaic.h:
*****************************************************************************
* Copyright (C) 2004-2005 VideoLAN
* $Id$
*
* Authors: Antoine Cellerier <dionoea@videolan.org>
* Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -21,24 +22,37 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#ifndef _PICTURE_VOUT_H
#define _PICTURE_VOUT_H 1
#define PICTURE_VOUT_E_AVAILABLE 0
#define PICTURE_VOUT_E_OCCUPIED 1
typedef struct picture_vout_e_t
typedef struct bridged_es_t
{
es_format_t fmt;
picture_t *p_picture;
int i_status;
picture_t **pp_last;
vlc_bool_t b_empty;
char *psz_id;
} picture_vout_e_t;
} bridged_es_t;
typedef struct bridge_t
{
bridged_es_t **pp_es;
int i_es_num;
} bridge_t;
typedef struct picture_vout_t
#define GetBridge(a) __GetBridge( VLC_OBJECT(a) )
static bridge_t *__GetBridge( vlc_object_t *p_object )
{
int i_picture_num;
picture_vout_e_t *p_pic;
} picture_vout_t;
libvlc_t *p_libvlc = p_object->p_libvlc;
bridge_t *p_bridge;
vlc_value_t val;
if( var_Get( p_libvlc, "mosaic-struct", &val ) != VLC_SUCCESS )
{
p_bridge = NULL;
}
else
{
p_bridge = val.p_address;
}
#undef IMAGE_2PASSES
return p_bridge;
}
#endif
......@@ -12,5 +12,3 @@ SOURCES_hd1000v = hd1000v.cpp
SOURCES_snapshot = snapshot.c
SOURCES_opengl = opengl.c
SOURCES_image = image.c
SOURCES_picture = picture.h \
picture.c
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