From ae42e9e71b81130e97ec3875cae5166907e9a062 Mon Sep 17 00:00:00 2001 From: Christophe Massiot Date: Mon, 7 Mar 2005 19:28:52 +0000 Subject: [PATCH] * src/video_output/vout_subpictures.c: New function spu_MakeRegion which reuses a given picture_t without allocating a new one. * modules/video_output/picture.c: New --picture-height and width options to do the scaling in the vout thread. Misc bug corrections. * modules/video_filter/mosaic.c: Less overhead. * modules/codec/ffmpeg/video_filter.c: Do the scaling before the conversion in case the original size is bigger than the destination. --- include/vlc_filter.h | 2 +- include/vlc_spu.h | 2 + include/vlc_video.h | 2 + modules/codec/ffmpeg/video_filter.c | 64 +++- modules/video_filter/mosaic.c | 522 +++++++++++++++------------- modules/video_output/picture.c | 410 ++++++++++++++++------ modules/video_output/picture.h | 15 +- src/video_output/vout_subpictures.c | 34 ++ 8 files changed, 676 insertions(+), 375 deletions(-) diff --git a/include/vlc_filter.h b/include/vlc_filter.h index 3e58c9ca3a..e99875a90e 100644 --- a/include/vlc_filter.h +++ b/include/vlc_filter.h @@ -1,5 +1,5 @@ /***************************************************************************** - * vlc_codec.h: codec related structures + * vlc_filter.h: filter related structures ***************************************************************************** * Copyright (C) 1999-2003 VideoLAN * $Id$ diff --git a/include/vlc_spu.h b/include/vlc_spu.h index bfb8e0ec47..afa33e1bfe 100644 --- a/include/vlc_spu.h +++ b/include/vlc_spu.h @@ -99,6 +99,8 @@ VLC_EXPORT( void, spu_DisplaySubpicture, ( spu_t *, subpicture_t * ) ); #define spu_CreateRegion(a,b) __spu_CreateRegion(VLC_OBJECT(a),b) VLC_EXPORT( subpicture_region_t *,__spu_CreateRegion, ( vlc_object_t *, video_format_t * ) ); +#define spu_MakeRegion(a,b,c) __spu_MakeRegion(VLC_OBJECT(a),b,c) +VLC_EXPORT( subpicture_region_t *,__spu_MakeRegion, ( vlc_object_t *, video_format_t *, picture_t * ) ); #define spu_DestroyRegion(a,b) __spu_DestroyRegion(VLC_OBJECT(a),b) VLC_EXPORT( void, __spu_DestroyRegion, ( vlc_object_t *, subpicture_region_t * ) ); diff --git a/include/vlc_video.h b/include/vlc_video.h index 0dd885e038..b5f21e4fa0 100644 --- a/include/vlc_video.h +++ b/include/vlc_video.h @@ -273,6 +273,8 @@ struct subpicture_t /** Pointer to functions for region management */ subpicture_region_t * ( *pf_create_region ) ( vlc_object_t *, video_format_t * ); + subpicture_region_t * ( *pf_make_region ) ( vlc_object_t *, + video_format_t *, picture_t * ); void ( *pf_destroy_region ) ( vlc_object_t *, subpicture_region_t * ); /** Private data - the subtitle plugin might want to put stuff here to diff --git a/modules/codec/ffmpeg/video_filter.c b/modules/codec/ffmpeg/video_filter.c index 0146116b5e..a3178691f3 100644 --- a/modules/codec/ffmpeg/video_filter.c +++ b/modules/codec/ffmpeg/video_filter.c @@ -113,9 +113,24 @@ int E_(OpenFilter)( vlc_object_t *p_this ) return VLC_EGENERIC; } - avpicture_alloc( &p_sys->tmp_pic, p_sys->i_dst_ffmpeg_chroma, - p_filter->fmt_in.video.i_width, - p_filter->fmt_in.video.i_height ); + if( p_sys->b_resize && p_sys->b_convert ) + { + if ( p_filter->fmt_in.video.i_width * p_filter->fmt_in.video.i_height > + p_filter->fmt_out.video.i_width * p_filter->fmt_out.video.i_height ) + { + /* Resizing then conversion */ + avpicture_alloc( &p_sys->tmp_pic, p_sys->i_src_ffmpeg_chroma, + p_filter->fmt_out.video.i_width, + p_filter->fmt_out.video.i_height ); + } + else + { + /* Conversion then resizing */ + avpicture_alloc( &p_sys->tmp_pic, p_sys->i_dst_ffmpeg_chroma, + p_filter->fmt_in.video.i_width, + p_filter->fmt_in.video.i_height ); + } + } msg_Dbg( p_filter, "input: %ix%i %4.4s -> %ix%i %4.4s", p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height, @@ -191,6 +206,7 @@ static picture_t *Process( filter_t *p_filter, picture_t *p_pic ) { filter_sys_t *p_sys = p_filter->p_sys; AVPicture src_pic, dest_pic, inter_pic; + AVPicture *p_src, *p_dst; picture_t *p_pic_dst; vlc_bool_t b_resize = p_sys->b_resize; int i; @@ -238,32 +254,42 @@ static picture_t *Process( filter_t *p_filter, picture_t *p_pic ) if( p_filter->fmt_in.video.i_bmask == 0x00ff0000 ) p_sys->i_src_ffmpeg_chroma = PIX_FMT_BGR24; -#if 0 - if( p_sys->b_resize && - p_filter->fmt_in.video.i_width * p_filter->fmt_in.video.i_height > - p_filter->fmt_out.video.i_width * p_filter->fmt_out.video.i_height ) + p_src = &src_pic; + + if( b_resize && p_sys->p_rsc ) { - img_resample( p_sys->p_rsc, &dest_pic, &p_sys->tmp_pic ); - b_resize = 0; + p_dst = &dest_pic; + if ( p_filter->fmt_in.video.i_width * p_filter->fmt_in.video.i_height > + p_filter->fmt_out.video.i_width * p_filter->fmt_out.video.i_height ) + { + if ( p_sys->b_convert ) p_dst = &p_sys->tmp_pic; + img_resample( p_sys->p_rsc, p_dst, p_src ); + b_resize = VLC_FALSE; + p_src = p_dst; + } } -#endif if( p_sys->b_convert ) { - if( p_sys->b_resize ) inter_pic = p_sys->tmp_pic; - else inter_pic = dest_pic; + video_format_t *p_fmt = &p_filter->fmt_out.video; + p_dst = &dest_pic; + if( b_resize ) + { + p_dst = &p_sys->tmp_pic; + p_fmt = &p_filter->fmt_in.video; + } - img_convert( &inter_pic, p_sys->i_dst_ffmpeg_chroma, - &src_pic, p_sys->i_src_ffmpeg_chroma, - p_filter->fmt_in.video.i_width, - p_filter->fmt_in.video.i_height ); + img_convert( p_dst, p_sys->i_dst_ffmpeg_chroma, + p_src, p_sys->i_src_ffmpeg_chroma, + p_fmt->i_width, p_fmt->i_height ); - src_pic = inter_pic; + p_src = p_dst; } - if( p_sys->b_resize && p_sys->p_rsc ) + if( b_resize && p_sys->p_rsc ) { - img_resample( p_sys->p_rsc, &dest_pic, &src_pic ); + p_dst = &dest_pic; + img_resample( p_sys->p_rsc, p_dst, p_src ); } /* Special case for RV32 -> YUVA */ diff --git a/modules/video_filter/mosaic.c b/modules/video_filter/mosaic.c index c3e41cd484..d54fecd9f5 100644 --- a/modules/video_filter/mosaic.c +++ b/modules/video_filter/mosaic.c @@ -1,29 +1,30 @@ /***************************************************************************** -* mosaic.c : Mosaic video plugin for vlc -***************************************************************************** -* Copyright (C) 2004-2005 VideoLAN -* $Id$ -* -* Authors: Antoine Cellerier -* -* 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 -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * mosaic.c : Mosaic video plugin for vlc + ***************************************************************************** + * Copyright (C) 2004-2005 VideoLAN + * $Id$ + * + * Authors: Antoine Cellerier + * Christophe Massiot + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************/ /***************************************************************************** -* Preamble -*****************************************************************************/ + * Preamble + *****************************************************************************/ #include /* malloc(), free() */ #include #include @@ -32,37 +33,35 @@ #include #include "vlc_filter.h" -#include "vlc_input.h" - #include "vlc_image.h" -/***************************************************************************** -* Local prototypes -*****************************************************************************/ +#include "../video_output/picture.h" +/***************************************************************************** + * Local prototypes + *****************************************************************************/ static int CreateFilter ( vlc_object_t * ); static void DestroyFilter ( vlc_object_t * ); static subpicture_t *Filter( filter_t *, mtime_t ); static int MosaicCallback( vlc_object_t *, char const *, vlc_value_t, - vlc_value_t, void * ); + vlc_value_t, void * ); /***************************************************************************** -* filter_sys_t : filter desriptor -*****************************************************************************/ - -#include "../video_output/picture.h" - + * filter_sys_t : filter descriptor + *****************************************************************************/ struct filter_sys_t { - image_handler_t *p_image; +#ifdef IMAGE_2PASSES image_handler_t *p_image2; +#endif picture_t *p_pic; - int i_pos; /* mosaic positioning method */ - int i_ar; /* do we keep aspect ratio ? */ + int i_position; /* mosaic positioning method */ + vlc_bool_t b_ar; /* do we keep the aspect ratio ? */ + vlc_bool_t b_keep; /* do we keep the original picture format ? */ int i_width, i_height; /* mosaic height and width */ int i_cols, i_rows; /* mosaic rows and cols */ int i_xoffset, i_yoffset; /* top left corner offset */ @@ -72,37 +71,45 @@ struct filter_sys_t char **ppsz_order; /* list of picture-id */ int i_order_length; + mtime_t i_delay; }; /***************************************************************************** -* Module descriptor -*****************************************************************************/ - -#define ALPHA_TEXT N_("Mosaic alpha blending (0 -> 255)") -#define ALPHA_LONGTEXT N_("Mosaic alpha blending (0 -> 255). default is 255") - -#define HEIGHT_TEXT N_("Mosaic height in pixels") -#define WIDTH_TEXT N_("Mosaic width in pixels") -#define XOFFSET_TEXT N_("Mosaic top left corner x coordinate") -#define YOFFSET_TEXT N_("Mosaic top left corner y coordinate") -#define VBORDER_TEXT N_("Mosaic vertical border width in pixels") -#define HBORDER_TEXT N_("Mosaic horizontal border width in pixels") - -#define POS_TEXT N_("Mosaic positioning method") -#define POS_LONGTEXT N_("Mosaic positioning method. auto : automatically chose the best number of rows and columns. fixed : used the user defined number of rows and columns.") -#define ROWS_TEXT N_("Mosaic number of rows") -#define COLS_TEXT N_("Mosaic number of columns") + * Module descriptor + *****************************************************************************/ +#define ALPHA_TEXT N_("Alpha blending") +#define ALPHA_LONGTEXT N_("Alpha blending (0 -> 255). Default is 255") + +#define HEIGHT_TEXT N_("Height in pixels") +#define WIDTH_TEXT N_("Width in pixels") +#define XOFFSET_TEXT N_("Top left corner x coordinate") +#define YOFFSET_TEXT N_("Top left corner y coordinate") +#define VBORDER_TEXT N_("Vertical border width in pixels") +#define HBORDER_TEXT N_("Horizontal border width in pixels") + +#define POS_TEXT N_("Positioning method") +#define POS_LONGTEXT N_("Positioning method. auto : automatically choose " \ + "the best number of rows and columns. fixed : use the user-defined " \ + "number of rows and columns.") +#define ROWS_TEXT N_("Number of rows") +#define COLS_TEXT N_("Number of columns") #define AR_TEXT N_("Keep aspect ratio when resizing") +#define KEEP_TEXT N_("Keep original size") #define ORDER_TEXT N_("Order as a comma separated list of picture-id(s)") +#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 " \ + "values you will need to raise file-caching and others.") + static int pi_pos_values[] = { 0, 1 }; static char * ppsz_pos_descriptions[] = { N_("auto"), N_("fixed") }; vlc_module_begin(); - set_description( _("Mosaic video sub filter") ); + set_description( N_("Mosaic video sub filter") ); set_shortname( N_("Mosaic") ); set_capability( "sub filter", 0 ); set_callbacks( CreateFilter, DestroyFilter ); @@ -120,18 +127,22 @@ vlc_module_begin(); add_integer( "mosaic-rows", 2, NULL, ROWS_TEXT, ROWS_TEXT, VLC_FALSE ); add_integer( "mosaic-cols", 2, NULL, COLS_TEXT, COLS_TEXT, VLC_FALSE ); add_bool( "mosaic-keep-aspect-ratio", 0, NULL, AR_TEXT, AR_TEXT, VLC_FALSE ); + 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, + VLC_FALSE ); vlc_module_end(); /***************************************************************************** -* CreateFiler: allocates mosaic video filter -*****************************************************************************/ - + * CreateFiler: allocate mosaic video filter + *****************************************************************************/ static int CreateFilter( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; filter_sys_t *p_sys; + libvlc_t *p_libvlc = p_filter->p_libvlc; char *psz_order; int i_index; @@ -142,39 +153,54 @@ static int CreateFilter( vlc_object_t *p_this ) msg_Err( p_filter, "out of memory" ); return VLC_ENOMEM; } - p_sys->p_image = image_HandlerCreate( p_filter ); - p_sys->p_image2 = image_HandlerCreate( p_filter ); p_filter->pf_sub_filter = Filter; p_sys->p_pic = NULL; - p_sys->i_width = __MAX( 0, var_CreateGetInteger( p_filter->p_libvlc, "mosaic-width" ) ); - p_sys->i_height = __MAX( 0, var_CreateGetInteger( p_filter->p_libvlc, "mosaic-height" ) ); - - p_sys->i_xoffset = __MAX( 0, var_CreateGetInteger( p_filter->p_libvlc, "mosaic-xoffset" ) ); - p_sys->i_yoffset = __MAX( 0, var_CreateGetInteger( p_filter->p_libvlc, "mosaic-yoffset" ) ); - - p_sys->i_vborder = __MAX( 0, var_CreateGetInteger( p_filter->p_libvlc, "mosaic-vborder" ) ); - p_sys->i_hborder = __MAX( 0, var_CreateGetInteger( p_filter->p_libvlc, "mosaic-hborder" ) ); - - p_sys->i_rows = __MAX( 1, var_CreateGetInteger( p_filter->p_libvlc, "mosaic-rows") ); - p_sys->i_cols = __MAX( 1, var_CreateGetInteger( p_filter->p_libvlc, "mosaic-cols") ); - - p_sys->i_alpha = var_CreateGetInteger( p_filter->p_libvlc, "mosaic-alpha" ); - p_sys->i_alpha = __MIN( 255, __MAX( 0, p_sys->i_alpha ) ); - - p_sys->i_pos = var_CreateGetInteger( p_filter->p_libvlc, "mosaic-position" ); - if( p_sys->i_pos > 1 || p_sys->i_pos < 0 ) p_sys->i_pos = 0; - - p_sys->i_ar = var_CreateGetInteger( p_filter->p_libvlc, "mosaic-keep-aspect-ratio" ); +#define GET_VAR( name, min, max ) \ + p_sys->i_##name = __MIN( max, __MAX( min, \ + var_CreateGetInteger( p_filter, "mosaic-" #name ) ) ); \ + var_Destroy( p_filter, "mosaic-" #name ); \ + var_Create( p_libvlc, "mosaic-" #name, VLC_VAR_INTEGER ); \ + var_SetInteger( p_libvlc, "mosaic-" #name, p_sys->i_##name ); \ + var_AddCallback( p_libvlc, "mosaic-" #name, MosaicCallback, p_sys ); + + GET_VAR( width, 0, INT32_MAX ); + GET_VAR( height, 0, INT32_MAX ); + GET_VAR( xoffset, 0, INT32_MAX ); + GET_VAR( yoffset, 0, INT32_MAX ); + GET_VAR( vborder, 0, INT32_MAX ); + GET_VAR( hborder, 0, INT32_MAX ); + GET_VAR( rows, 1, INT32_MAX ); + GET_VAR( cols, 1, INT32_MAX ); + GET_VAR( alpha, 0, 255 ); + GET_VAR( position, 0, 1 ); + GET_VAR( delay, 100, INT32_MAX ); + p_sys->i_delay *= 1000; + + p_sys->b_ar = var_CreateGetBool( p_filter, "mosaic-keep-aspect-ratio" ); + var_Destroy( p_filter, "mosaic-keep-aspect-ratio" ); + var_Create( p_libvlc, "mosaic-keep-aspect-ratio", VLC_VAR_INTEGER ); + var_SetBool( p_libvlc, "mosaic-keep-aspect-ratio", p_sys->b_ar ); + var_AddCallback( p_libvlc, "mosaic-keep-aspect-ratio", MosaicCallback, + p_sys ); + + p_sys->b_keep = var_CreateGetBool( p_filter, "mosaic-keep-picture" ); + 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; p_sys->ppsz_order = NULL; - psz_order = var_CreateGetString( p_filter->p_libvlc, "mosaic-order" ); + psz_order = var_CreateGetString( p_filter, "mosaic-order" ); if( psz_order[0] != 0 ) { - char* psz_end=NULL; + char *psz_end = NULL; i_index = 0; do { @@ -189,44 +215,28 @@ static int CreateFilter( vlc_object_t *p_this ) p_sys->i_order_length = i_index; } - var_AddCallback( p_filter->p_libvlc, "mosaic-alpha", - MosaicCallback, p_sys ); - var_AddCallback( p_filter->p_libvlc, "mosaic-height", - MosaicCallback, p_sys ); - var_AddCallback( p_filter->p_libvlc, "mosaic-width", - MosaicCallback, p_sys ); - var_AddCallback( p_filter->p_libvlc, "mosaic-xoffset", - MosaicCallback, p_sys ); - var_AddCallback( p_filter->p_libvlc, "mosaic-yoffset", - MosaicCallback, p_sys ); - var_AddCallback( p_filter->p_libvlc, "mosaic-vborder", - MosaicCallback, p_sys ); - var_AddCallback( p_filter->p_libvlc, "mosaic-hborder", - MosaicCallback, p_sys ); - var_AddCallback( p_filter->p_libvlc, "mosaic-position", - MosaicCallback, p_sys ); - var_AddCallback( p_filter->p_libvlc, "mosaic-rows", - MosaicCallback, p_sys ); - var_AddCallback( p_filter->p_libvlc, "mosaic-cols", - MosaicCallback, p_sys ); - var_AddCallback( p_filter->p_libvlc, "mosaic-keep-aspect-ratio", - MosaicCallback, p_sys ); + vlc_thread_set_priority( p_filter, VLC_THREAD_PRIORITY_OUTPUT ); return VLC_SUCCESS; } /***************************************************************************** -* DestroyFilter: destroy mosaic video filter -*****************************************************************************/ - + * DestroyFilter: destroy mosaic video filter + *****************************************************************************/ static void DestroyFilter( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t*)p_this; filter_sys_t *p_sys = p_filter->p_sys; + libvlc_t *p_libvlc = p_filter->p_libvlc; int i_index; - image_HandlerDelete( p_sys->p_image ); - image_HandlerDelete( p_sys->p_image2 ); + 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 ) { @@ -237,43 +247,63 @@ static void DestroyFilter( vlc_object_t *p_this ) free( p_sys->ppsz_order ); } - var_Destroy( p_filter->p_libvlc, "mosaic-alpha" ); - var_Destroy( p_filter->p_libvlc, "mosaic-height" ); - var_Destroy( p_filter->p_libvlc, "mosaic-width" ); - var_Destroy( p_filter->p_libvlc, "mosaic-xoffset" ); - var_Destroy( p_filter->p_libvlc, "mosaic-yoffset" ); - var_Destroy( p_filter->p_libvlc, "mosaic-vborder" ); - var_Destroy( p_filter->p_libvlc, "mosaic-hborder" ); - var_Destroy( p_filter->p_libvlc, "mosaic-position" ); - var_Destroy( p_filter->p_libvlc, "mosaic-rows" ); - var_Destroy( p_filter->p_libvlc, "mosaic-cols" ); - var_Destroy( p_filter->p_libvlc, "mosaic-keep-aspect-ratio" ); + var_Destroy( p_libvlc, "mosaic-alpha" ); + var_Destroy( p_libvlc, "mosaic-height" ); + var_Destroy( p_libvlc, "mosaic-width" ); + var_Destroy( p_libvlc, "mosaic-xoffset" ); + var_Destroy( p_libvlc, "mosaic-yoffset" ); + var_Destroy( p_libvlc, "mosaic-vborder" ); + var_Destroy( p_libvlc, "mosaic-hborder" ); + var_Destroy( p_libvlc, "mosaic-position" ); + var_Destroy( p_libvlc, "mosaic-rows" ); + var_Destroy( p_libvlc, "mosaic-cols" ); + var_Destroy( p_libvlc, "mosaic-keep-aspect-ratio" ); + if( p_sys->p_pic ) p_sys->p_pic->pf_release( p_sys->p_pic ); free( p_sys ); } /***************************************************************************** -* Filter -*****************************************************************************/ + * MosaicReleasePicture : Hack to avoid picture duplication + *****************************************************************************/ +static void MosaicReleasePicture( picture_t *p_picture ) +{ + picture_t *p_original_pic = (picture_t *)p_picture->p_sys; + + p_original_pic->pf_release( p_original_pic ); +} +/***************************************************************************** + * Filter + *****************************************************************************/ 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; + subpicture_t *p_spu; - libvlc_t *p_libvlc = p_filter->p_libvlc; - vlc_value_t val; int i_index, i_real_index, i_row, i_col; int i_greatest_real_index_used = p_sys->i_order_length - 1; subpicture_region_t *p_region; subpicture_region_t *p_region_prev = NULL; - struct picture_vout_t *p_picture_vout; + 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; } @@ -293,29 +323,29 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date ) p_spu->b_ephemer = VLC_TRUE; p_spu->i_alpha = p_sys->i_alpha; - vlc_mutex_lock( &p_picture_vout->lock ); - - if( p_sys->i_pos == 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_picture_vout->i_picture_num; + i_index++ ) { if( p_picture_vout->p_pic[i_index].i_status - == PICTURE_VOUT_E_OCCUPIED ) { + == PICTURE_VOUT_E_OCCUPIED ) + { i_numpics ++; if( p_sys->i_order_length - && p_picture_vout->p_pic[i_index].psz_id != 0 ){ - /* we also want to leave slots for images given in mosaic-order - that are not available in p_vout_picture */ + && p_picture_vout->p_pic[i_index].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_picture_vout->p_pic[i_index].psz_id ) ) { - i_numpics --; + i_numpics--; break; } } @@ -324,41 +354,40 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date ) } } p_sys->i_rows = ((int)ceil(sqrt( (float)i_numpics ))); - p_sys->i_cols = ( i_numpics%p_sys->i_rows == 0 ? - i_numpics/p_sys->i_rows : - i_numpics/p_sys->i_rows + 1 ); + p_sys->i_cols = ( i_numpics % p_sys->i_rows == 0 ? + i_numpics / p_sys->i_rows : + i_numpics / p_sys->i_rows + 1 ); } 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_picture_vout->i_picture_num; i_index++ ) { - - video_format_t fmt_in = {0}, fmt_middle = {0}, fmt_out = {0}; - - picture_t *p_converted, *p_middle; - - if( p_picture_vout->p_pic[i_index].p_picture == NULL ) + picture_vout_e_t *p_pic = &p_picture_vout->p_pic[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 ) { - break; + continue; } - if( p_picture_vout->p_pic[i_index].i_status - == PICTURE_VOUT_E_AVAILABLE ) + if( p_sys->i_order_length == 0 ) { - msg_Dbg( p_filter, "Picture Vout Element is empty"); - break; + i_real_index++; } - 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_picture_vout->p_pic[i_index].psz_id, - p_sys->ppsz_order[ i ] ) == 0 ) + if( strcmp( p_pic->psz_id, p_sys->ppsz_order[i] ) == 0 ) { i_real_index = i; break; @@ -367,96 +396,120 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date ) 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_row = ( i_real_index / p_sys->i_cols ) % p_sys->i_rows; i_col = i_real_index % p_sys->i_cols ; - /* Convert the images */ -/* fprintf (stderr, "Input image %ix%i %4.4s\n", - p_picture_vout->p_pic[i_index].p_picture->format.i_width, - p_picture_vout->p_pic[i_index].p_picture->format.i_height, - (char *)&p_picture_vout->p_pic[i_index].p_picture->format.i_chroma );*/ - - fmt_in.i_chroma = p_picture_vout->p_pic[i_index]. - p_picture->format.i_chroma; - fmt_in.i_height = p_picture_vout->p_pic[i_index]. - p_picture->format.i_height; - fmt_in.i_width = p_picture_vout->p_pic[i_index]. - p_picture->format.i_width; - - - fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A'); - fmt_out.i_width = fmt_in.i_width * - ( ( p_sys->i_width - ( p_sys->i_cols - 1 ) * p_sys->i_vborder ) - / p_sys->i_cols ) / fmt_in.i_width; - fmt_out.i_height = fmt_in.i_height * - ( ( p_sys->i_height - ( p_sys->i_rows - 1 ) * p_sys->i_hborder ) - / p_sys->i_rows ) / fmt_in.i_height; - if( p_sys->i_ar ) /* keep aspect ratio */ + if( !p_sys->b_keep ) { - if( (float)fmt_out.i_width/(float)fmt_out.i_height - > (float)fmt_in.i_width/(float)fmt_in.i_height ) + /* 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_out.i_chroma = VLC_FOURCC('Y','U','V','A'); + fmt_out.i_width = fmt_in.i_width * + ( ( p_sys->i_width - ( p_sys->i_cols - 1 ) * p_sys->i_vborder ) + / p_sys->i_cols ) / fmt_in.i_width; + fmt_out.i_height = fmt_in.i_height * + ( ( p_sys->i_height - ( p_sys->i_rows - 1 ) * p_sys->i_hborder ) + / p_sys->i_rows ) / fmt_in.i_height; + if( p_sys->b_ar ) /* keep aspect ratio */ { - fmt_out.i_width = ( fmt_out.i_height * fmt_in.i_width ) / fmt_in.i_height ; - } else { - fmt_out.i_height = ( fmt_out.i_width * fmt_in.i_height ) / fmt_in.i_width ; - } - } + if( (float)fmt_out.i_width / (float)fmt_out.i_height + > (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 ; + } + else + { + fmt_out.i_height = ( fmt_out.i_width * fmt_in.i_height ) + / fmt_in.i_width ; + } + } - fmt_out.i_visible_width = fmt_out.i_width; - fmt_out.i_visible_height = fmt_out.i_height; + fmt_out.i_visible_width = fmt_out.i_width; + fmt_out.i_visible_height = fmt_out.i_height; - 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; +#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_image, - p_picture_vout->p_pic[i_index].p_picture, &fmt_in, &fmt_middle ); - if( !p_middle ) - { - msg_Err( p_filter, "image resizing failed" ); - p_filter->pf_sub_buffer_del( p_filter, p_spu ); - vlc_mutex_unlock( &p_picture_vout->lock ); - return NULL; - } + 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_image2, - p_middle, &fmt_middle, &fmt_out ); - if( !p_converted ) + p_converted = image_Convert( p_sys->p_image, p_middle, + &fmt_middle, &fmt_out ); + p_middle->pf_release( p_middle ); +#else + p_converted = image_Convert( p_sys->p_image, p_pic->p_picture, + &fmt_in, &fmt_out ); +#endif + if( !p_converted ) + { + msg_Warn( p_filter, "image chroma conversion failed" ); + continue; + } + } + else { - msg_Err( p_filter, "image chroma convertion failed" ); - p_filter->pf_sub_buffer_del( p_filter, p_spu ); - vlc_mutex_unlock( &p_picture_vout->lock ); - return NULL; + p_converted = p_pic->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; + fmt_in.i_chroma = fmt_out.i_chroma = p_converted->format.i_chroma; + fmt_out.i_visible_width = fmt_out.i_width; + fmt_out.i_visible_height = fmt_out.i_height; } -/* fprintf( stderr, "Converted %ix%i %4.4s\n", p_converted->format.i_width, p_converted->format.i_height, (char *)&p_converted->format.i_chroma);*/ - - - p_region = p_spu->pf_create_region( VLC_OBJECT(p_filter), &fmt_out); + p_region = p_spu->pf_make_region( VLC_OBJECT(p_filter), &fmt_out, + p_converted ); if( !p_region ) { msg_Err( p_filter, "cannot allocate SPU region" ); p_filter->pf_sub_buffer_del( p_filter, p_spu ); - vlc_mutex_unlock( &p_picture_vout->lock ); + vlc_mutex_unlock( lockval.p_address ); return NULL; } - if( p_sys->i_ar ) /* keep aspect ratio */ + /* HACK ALERT : let's fix the pointers to avoid picture duplication. + * This is necessary because p_region->picture is not a pointer + * as it ought to be. */ + if( !p_sys->b_keep ) + { + free( p_converted ); + } + else + { + /* Keep a pointer to the original picture (and its refcount...). */ + p_region->picture.p_sys = (picture_sys_t *)p_converted; + p_region->picture.pf_release = MosaicReleasePicture; + } + + if( p_sys->b_ar || p_sys->b_keep ) /* keep aspect ratio */ { /* center the video in the dedicated rectangle */ p_region->i_x = p_sys->i_xoffset - + i_col * ( p_sys->i_width / p_sys->i_cols ) - + ( i_col * p_sys->i_vborder ) / p_sys->i_cols - + ( fmt_in.i_width * - ( ( p_sys->i_width - ( p_sys->i_cols - 1 ) * p_sys->i_vborder ) - / p_sys->i_cols ) / fmt_in.i_width - fmt_out.i_width ) / 2; + + i_col * ( p_sys->i_width / p_sys->i_cols ) + + ( i_col * p_sys->i_vborder ) / p_sys->i_cols + + ( ( ( p_sys->i_width + - ( p_sys->i_cols - 1 ) * p_sys->i_vborder ) + / p_sys->i_cols ) - fmt_out.i_width ) / 2; p_region->i_y = p_sys->i_yoffset + i_row * ( p_sys->i_height / p_sys->i_rows ) + ( i_row * p_sys->i_hborder ) / p_sys->i_rows - + ( fmt_in.i_height * - ( ( p_sys->i_height - ( p_sys->i_rows - 1 ) * p_sys->i_hborder ) - / p_sys->i_rows ) / fmt_in.i_height - fmt_out.i_height ) / 2; - } else { + + ( ( ( p_sys->i_height + - ( p_sys->i_rows - 1 ) * p_sys->i_hborder ) + / p_sys->i_rows ) - fmt_out.i_height ) / 2; + } + else + { /* we don't have to center the video since it takes the whole rectangle area */ p_region->i_x = p_sys->i_xoffset @@ -467,21 +520,19 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date ) + ( i_row * p_sys->i_hborder ) / p_sys->i_rows; } - if( p_region_prev == NULL ){ + if( p_region_prev == NULL ) + { p_spu->p_region = p_region; - } else { + } + else + { p_region_prev->p_next = p_region; } p_region_prev = p_region; - - vout_CopyPicture( p_filter, &p_region->picture, p_converted ); - - p_middle->pf_release( p_middle ); - p_converted->pf_release( p_converted ); } - vlc_mutex_unlock( &p_picture_vout->lock ); + vlc_mutex_unlock( lockval.p_address ); return p_spu; } @@ -489,7 +540,6 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date ) /***************************************************************************** * Callback to update params on the fly *****************************************************************************/ - static int MosaicCallback( vlc_object_t *p_this, char const *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data ) @@ -546,9 +596,9 @@ static int MosaicCallback( vlc_object_t *p_this, char const *psz_var, else { msg_Dbg( p_this, "Changing position method from %d (%s) to %d (%s)", - p_sys->i_pos, ppsz_pos_descriptions[p_sys->i_pos], + p_sys->i_position, ppsz_pos_descriptions[p_sys->i_position], newval.i_int, ppsz_pos_descriptions[newval.i_int]); - p_sys->i_pos = newval.i_int; + p_sys->i_position = newval.i_int; } } else if( !strcmp( psz_var, "mosaic-rows" ) ) @@ -568,12 +618,12 @@ static int MosaicCallback( vlc_object_t *p_this, char const *psz_var, if( newval.i_int ) { msg_Dbg( p_this, "Keep aspect ratio" ); - p_sys->i_ar = 1; + p_sys->b_ar = 1; } else { msg_Dbg( p_this, "Don't keep aspect ratio" ); - p_sys->i_ar = 0; + p_sys->b_ar = 0; } } return VLC_SUCCESS; diff --git a/modules/video_output/picture.c b/modules/video_output/picture.c index 4f7ee5269e..f36ab2157b 100644 --- a/modules/video_output/picture.c +++ b/modules/video_output/picture.c @@ -5,6 +5,7 @@ * $Id: picture.c 10081 2005-03-01 15:33:51Z dionoea $ * * Authors: Antoine Cellerier + * Christophe Massiot * * 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 @@ -29,31 +30,57 @@ #include /* strerror() */ #include -#include #include -#include -#include -#ifndef WIN32 -# include /* BSD: struct in_addr */ -#endif +#include "vlc_image.h" + +#include "picture.h" -/*********************************************************************** -* -***********************************************************************/ +/***************************************************************************** + * Local structures + *****************************************************************************/ struct vout_sys_t { + picture_vout_t *p_picture_vout; + 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 + int i_height, i_width; + mtime_t i_last_pic; }; -#include "picture.h" +/* Delay after which the picture is blanked out if there hasn't been any + * new picture. */ +#define BLANK_DELAY I64C(1000000) -#define ID_TEXT N_("ID") +typedef void (* pf_release_t)( picture_t * ); +static void ReleasePicture( picture_t *p_pic ) +{ + p_pic->i_refcount--; -/*********************************************************************** -* Local prototypes -***********************************************************************/ + if ( p_pic->i_refcount <= 0 ) + { + if ( p_pic->p_sys != NULL ) + { + pf_release_t pf_release = (pf_release_t)p_pic->p_sys; + p_pic->p_sys = NULL; + pf_release( p_pic ); + } + else + { + if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig ); + if( p_pic ) free( p_pic ); + } + } +} +/***************************************************************************** + * Local prototypes + *****************************************************************************/ static int Open ( vlc_object_t * ); static void Close ( vlc_object_t * ); static int Init ( vout_thread_t * ); @@ -61,45 +88,71 @@ static void End ( vout_thread_t * ); static int Manage ( vout_thread_t * ); static void Display ( vout_thread_t *, picture_t * ); -/*********************************************************************** -* Module descriptor -***********************************************************************/ +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define ID_TEXT N_("ID") +#define ID_LONGTEXT N_( \ + "Specify an identifier string for this subpicture" ) + +#define WIDTH_TEXT N_("Video width") +#define WIDTH_LONGTEXT N_( \ + "Allows you to specify the output video width." ) +#define HEIGHT_TEXT N_("Video height") +#define HEIGHT_LONGTEXT N_( \ + "Allows you to specify the output video height." ) + vlc_module_begin(); - set_description(_("VLC Internal Picture video output") ); - set_capability( "video output", 70 ); + set_shortname( _( "Picture" ) ); + set_description(_("VLC internal picture video output") ); + set_category( CAT_VIDEO ); + set_subcategory( SUBCAT_VIDEO_VOUT ); + set_capability( "video output", 0 ); + + add_string( "picture-id", "Id", NULL, ID_TEXT, ID_LONGTEXT, VLC_FALSE ); + add_integer( "picture-width", 0, NULL, WIDTH_TEXT, + WIDTH_LONGTEXT, VLC_TRUE ); + add_integer( "picture-height", 0, NULL, HEIGHT_TEXT, + HEIGHT_LONGTEXT, VLC_TRUE ); + set_callbacks( Open, Close ); - add_string( "picture-id", "Id", NULL, ID_TEXT, ID_TEXT, VLC_FALSE ); + + var_Create( p_module->p_libvlc, "picture-lock", VLC_VAR_MUTEX ); vlc_module_end(); -/*********************************************************************** -* Open : allocate video thread output method -***********************************************************************/ -static int Open ( vlc_object_t *p_this ) +/***************************************************************************** + * Open : allocate video thread output method + *****************************************************************************/ +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; - struct picture_vout_t *p_picture_vout = NULL; - vlc_value_t val; + picture_vout_t *p_picture_vout = NULL; + picture_vout_e_t *p_pic; + vlc_value_t val, lockval; - p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); - if( p_vout->p_sys == NULL ) + 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; } + var_Get( p_libvlc, "picture-lock", &lockval ); + p_sys->p_lock = lockval.p_address; + vlc_mutex_lock( p_sys->p_lock ); + + p_sys->i_picture_pos = -1; if( var_Get( p_libvlc, "p_picture_vout", &val ) != VLC_SUCCESS ) { - msg_Dbg( p_vout, "p_picture_vout not found" ); p_picture_vout = malloc( sizeof( struct picture_vout_t ) ); - if( p_vout->p_sys == NULL ) + if( p_picture_vout == NULL ) { msg_Err( p_vout, "out of memory" ); return VLC_ENOMEM; } - vlc_mutex_init( p_libvlc, &p_picture_vout->lock ); - vlc_mutex_lock( &p_picture_vout->lock ); var_Create( p_libvlc, "p_picture_vout", VLC_VAR_ADDRESS ); val.p_address = p_picture_vout; var_Set( p_libvlc, "p_picture_vout", val ); @@ -109,30 +162,56 @@ static int Open ( vlc_object_t *p_this ) } else { + int i; p_picture_vout = val.p_address; - msg_Dbg( p_vout, "p_picture_vout found" ); - vlc_mutex_lock( &p_picture_vout->lock ); + 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_vout->p_sys->i_picture_pos = p_picture_vout->i_picture_num; + p_sys->p_picture_vout = p_picture_vout; - p_picture_vout->p_pic = realloc( p_picture_vout->p_pic, - (p_picture_vout->i_picture_num+1) * sizeof( struct picture_vout_e_t ) ); + 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_picture_vout->p_pic[p_picture_vout->i_picture_num].p_picture = NULL; - p_picture_vout->p_pic[p_picture_vout->i_picture_num].i_status - = PICTURE_VOUT_E_OCCUPIED; + 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_Create( p_vout, "picture-id", VLC_VAR_STRING ); - var_Change( p_vout, "picture-id", VLC_VAR_INHERITVALUE, &val, NULL); - p_picture_vout->p_pic[p_picture_vout->i_picture_num].psz_id - = (char *)malloc( sizeof(char) * ( strlen( val.psz_string) + 1 ) ); - strcpy( p_picture_vout->p_pic[p_picture_vout->i_picture_num].psz_id, - val.psz_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 ); - p_picture_vout->i_picture_num++; + var_Create( p_vout, "picture-height", VLC_VAR_INTEGER ); + var_Change( p_vout, "picture-height", VLC_VAR_INHERITVALUE, &val, NULL ); + 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 ); + 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 + } - vlc_mutex_unlock( &p_picture_vout->lock ); + p_sys->i_last_pic = 0; p_vout->pf_init = Init; p_vout->pf_end = End; @@ -144,12 +223,11 @@ static int Open ( vlc_object_t *p_this ) } -/*********************************************************************** -* Init -***********************************************************************/ +/***************************************************************************** + * Init + *****************************************************************************/ static int Init( vout_thread_t *p_vout ) { - picture_t *p_pic; int i_index; @@ -200,109 +278,215 @@ static int Init( vout_thread_t *p_vout ) } -/*********************************************************************** -* End -***********************************************************************/ +/***************************************************************************** + * End + *****************************************************************************/ static void End( vout_thread_t *p_vout ) { return; } -/*********************************************************************** -* Close -***********************************************************************/ -static void Close ( vlc_object_t *p_this ) +/***************************************************************************** + * Close + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) { - vout_thread_t * p_vout = (vout_thread_t *)p_this; - - libvlc_t *p_libvlc = p_vout->p_libvlc; - struct picture_vout_t *p_picture_vout = NULL; - vlc_value_t val; - int i_flag=0, i; - - msg_Dbg( p_vout, "Closing Picture Vout ..."); - var_Get( p_libvlc, "p_picture_vout", &val ); - p_picture_vout = val.p_address; + 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; + int i; - vlc_mutex_lock( &p_picture_vout->lock ); + vlc_mutex_lock( p_sys->p_lock ); + p_pic = &p_picture_vout->p_pic[p_sys->i_picture_pos]; - if( p_picture_vout->p_pic[p_vout->p_sys->i_picture_pos].p_picture ) + if( p_pic->p_picture ) { - /* FIXME */ - free( p_picture_vout->p_pic[p_vout->p_sys->i_picture_pos].p_picture ); + p_pic->p_picture->pf_release( p_pic->p_picture ); + p_pic->p_picture = NULL; } - p_picture_vout->p_pic[p_vout->p_sys->i_picture_pos].i_status - = PICTURE_VOUT_E_AVAILABLE; + 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 ++) { if( p_picture_vout->p_pic[i].i_status == PICTURE_VOUT_E_OCCUPIED ) { - i_flag = 1; + b_last_picture = VLC_FALSE; break; } } - if( i_flag == 1 ) + if( b_last_picture ) { - vlc_mutex_unlock( &p_picture_vout->lock ); + free( p_picture_vout->p_pic ); + free( p_picture_vout ); + var_Destroy( p_this->p_libvlc, "p_picture_vout" ); } - else + + vlc_mutex_unlock( p_sys->p_lock ); + + if ( p_sys->i_height || p_sys->i_width ) { - free( p_picture_vout->p_pic ); - vlc_mutex_unlock( &p_picture_vout->lock ); - vlc_mutex_destroy( &p_picture_vout->lock ); - var_Destroy( p_libvlc, "p_picture_vout" ); + image_HandlerDelete( p_sys->p_image ); +#ifdef IMAGE_2PASSES + image_HandlerDelete( p_sys->p_image2 ); +#endif + } + + free( p_sys ); +} + +/***************************************************************************** + * PushPicture : push a picture in the p_picture_vout structure + *****************************************************************************/ +static void PushPicture( vout_thread_t *p_vout, 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; + + 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; - free( p_vout->p_sys ); + vlc_mutex_unlock( p_sys->p_lock ); } -/*********************************************************************** -* Manage -***********************************************************************/ +/***************************************************************************** + * Manage + *****************************************************************************/ static int Manage( vout_thread_t *p_vout ) { + vout_sys_t *p_sys = p_vout->p_sys; + + if ( mdate() - p_sys->i_last_pic > BLANK_DELAY ) + { + /* Display black */ +#if 0 + picture_t *p_new_pic = (picture_t*)malloc( sizeof(picture_t) ); + int i; + + 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 ); + } + 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->i_refcount++; + p_new_pic->i_status = DESTROYED_PICTURE; + p_new_pic->i_type = DIRECT_PICTURE; + p_new_pic->pf_release = ReleasePicture; + + 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; + } + return VLC_SUCCESS; } -/*********************************************************************** -* Display -***********************************************************************/ +/***************************************************************************** + * Display + *****************************************************************************/ static void Display( vout_thread_t *p_vout, picture_t *p_pic ) { - libvlc_t *p_libvlc = p_vout->p_libvlc; - vlc_value_t val; - struct picture_vout_t *p_picture_vout; + vout_sys_t *p_sys = p_vout->p_sys; picture_t *p_new_pic; - var_Get( p_libvlc, "p_picture_vout", &val ); - p_picture_vout = val.p_address; + if ( p_sys->i_height || p_sys->i_width ) + { + video_format_t fmt_out = {0}, fmt_in = {0}; +#ifdef IMAGE_2PASSES + vide_format_t fmt_middle = {0}; + picture_t *p_new_pic2; +#endif - 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, - VOUT_ASPECT_FACTOR * p_pic->format.i_height / p_pic->format.i_width ); + fmt_in.i_chroma = p_vout->render.i_chroma; + fmt_in.i_width = p_vout->render.i_width; + fmt_in.i_height = p_vout->render.i_height; - p_new_pic->i_status = DESTROYED_PICTURE; - p_new_pic->i_type = DIRECT_PICTURE; +#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; - vout_CopyPicture( p_vout, p_new_pic, p_pic ); + p_new_pic2 = image_Convert( p_vout->p_sys->p_image2, + p_pic, &fmt_in, &fmt_middle ); + if ( p_new_pic2 == NULL ) + { + 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; + } +#endif - vlc_mutex_lock( &p_picture_vout->lock ); - if( p_picture_vout->p_pic[p_vout->p_sys->i_picture_pos].p_picture ) - { - if( p_picture_vout->p_pic[p_vout->p_sys->i_picture_pos].p_picture->p_data_orig ) + 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 ) { - free( p_picture_vout->p_pic[p_vout->p_sys->i_picture_pos] - .p_picture->p_data_orig ); + msg_Err( p_vout, "image conversion failed" ); + return; } - free( p_picture_vout->p_pic[p_vout->p_sys->i_picture_pos].p_picture ); } - p_picture_vout->p_pic[p_vout->p_sys->i_picture_pos].p_picture = p_new_pic; + 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_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; - vlc_mutex_unlock( &p_picture_vout->lock ); + PushPicture( p_vout, p_new_pic ); + p_sys->i_last_pic = p_pic->date; } diff --git a/modules/video_output/picture.h b/modules/video_output/picture.h index 6742c86ecb..d1681d414b 100644 --- a/modules/video_output/picture.h +++ b/modules/video_output/picture.h @@ -26,16 +26,19 @@ #define PICTURE_VOUT_E_AVAILABLE 0 #define PICTURE_VOUT_E_OCCUPIED 1 -struct picture_vout_e_t { +typedef struct picture_vout_e_t +{ picture_t *p_picture; int i_status; char *psz_id; -}; -struct picture_vout_t +} picture_vout_e_t; + +typedef struct picture_vout_t { - vlc_mutex_t lock; int i_picture_num; - struct picture_vout_e_t *p_pic; -}; + picture_vout_e_t *p_pic; +} picture_vout_t; + +#undef IMAGE_2PASSES #endif diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c index 9cd81136d2..e03f21518b 100644 --- a/src/video_output/vout_subpictures.c +++ b/src/video_output/vout_subpictures.c @@ -285,6 +285,38 @@ subpicture_region_t *__spu_CreateRegion( vlc_object_t *p_this, return p_region; } +/** + * Make a subpicture region from an existing picture_t + * + * \param p_this vlc_object_t + * \param p_fmt the format that this subpicture region should have + * \param p_pic a pointer to the picture creating the region (not freed) + */ +subpicture_region_t *__spu_MakeRegion( vlc_object_t *p_this, + video_format_t *p_fmt, + picture_t *p_pic ) +{ + subpicture_region_t *p_region = malloc( sizeof(subpicture_region_t) ); + memset( p_region, 0, sizeof(subpicture_region_t) ); + p_region->p_next = 0; + p_region->p_cache = 0; + p_region->fmt = *p_fmt; + p_region->psz_text = 0; + p_region->i_font_color = -1; /* default to using freetype-color -opacity */ + p_region->i_font_opacity = -1; + p_region->i_font_size = -1; /* and the freetype fontsize */ + + if( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) + p_fmt->p_palette = p_region->fmt.p_palette = + malloc( sizeof(video_palette_t) ); + else p_fmt->p_palette = p_region->fmt.p_palette = NULL; + + memcpy( &p_region->picture, p_pic, sizeof(picture_t) ); + p_region->picture.pf_release = RegionPictureRelease; + + return p_region; +} + /** * Destroy a subpicture region * @@ -384,6 +416,7 @@ subpicture_t *spu_CreateSubpicture( spu_t *p_spu ) vlc_mutex_unlock( &p_spu->subpicture_lock ); p_subpic->pf_create_region = __spu_CreateRegion; + p_subpic->pf_make_region = __spu_MakeRegion; p_subpic->pf_destroy_region = __spu_DestroyRegion; return p_subpic; @@ -1011,6 +1044,7 @@ static subpicture_t *spu_new_buffer( filter_t *p_filter ) p_subpic->b_absolute = VLC_TRUE; p_subpic->pf_create_region = __spu_CreateRegion; + p_subpic->pf_make_region = __spu_MakeRegion; p_subpic->pf_destroy_region = __spu_DestroyRegion; return p_subpic; -- 2.39.2