From: Jean-Paul Saman Date: Wed, 9 Apr 2008 10:45:24 +0000 (+0200) Subject: Merge branch 'dynamicoverlay' X-Git-Tag: 0.9.0-test0~1495 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=1ac8441a1c11c1c242a4c5ad7ed9918fbf14da37;hp=665cd9209c6227c1bf494b47f40d7fd52d3cee59;p=vlc Merge branch 'dynamicoverlay' --- diff --git a/THANKS b/THANKS index 0ccd7abeed..60cf28afa1 100644 --- a/THANKS +++ b/THANKS @@ -208,6 +208,7 @@ Sebastian Jenny - AAC decoding channel order Sebastien Chaumat - YOPY port tests Sidney Doria - Brazilian Portuguese localisation Simon Damkjær Andersen - playmode icons and the entire Fullscreen Panel design for the OSX GUI (v0.8.6) +Soren Bog - dynamicoverlays Stefán Freyr Stefánsson - Qt4 speed slider Steve Lhomme - MSVC fixes and Matroska enhancements Steve Brown - fix for optional PES size bug diff --git a/configure.ac b/configure.ac index e5847113e1..1160a61d8a 100644 --- a/configure.ac +++ b/configure.ac @@ -1200,7 +1200,7 @@ dnl VLC_ADD_PLUGINS([dummy logger memcpy]) VLC_ADD_PLUGINS([mpgv mpga m4v m4a h264 vc1 demux_cdg cdg ps pva avi asf mp4 rawdv rawvid nsv real aiff mjpeg demuxdump flacsys tta]) VLC_ADD_PLUGINS([cvdsub svcdsub spudec subsdec subsusf t140 dvbsub cc mpeg_audio lpcm a52 dts cinepak flac]) -VLC_ADD_PLUGINS([deinterlace invert adjust transform wave ripple psychedelic gradient motionblur rv32 rotate noise grain extract sharpen seamcarving croppadd]) +VLC_ADD_PLUGINS([deinterlace invert adjust transform wave ripple psychedelic gradient motionblur rv32 rotate noise grain extract sharpen seamcarving croppadd dynamicoverlay blendbench]) VLC_ADD_PLUGINS([converter_fixed mono]) VLC_ADD_PLUGINS([trivial_resampler ugly_resampler]) VLC_ADD_PLUGINS([trivial_channel_mixer trivial_mixer]) @@ -6294,6 +6294,7 @@ AC_CONFIG_FILES([ modules/video_chroma/Makefile modules/video_filter/Makefile modules/video_filter/atmo/Makefile + modules/video_filter/dynamicoverlay/Makefile modules/video_output/Makefile modules/video_output/msw/Makefile modules/video_output/qte/Makefile diff --git a/include/vlc_vout.h b/include/vlc_vout.h index 30baf25178..601baa576e 100644 --- a/include/vlc_vout.h +++ b/include/vlc_vout.h @@ -211,10 +211,11 @@ struct subpicture_region_t int i_x; /**< position of region */ int i_y; /**< position of region */ int i_align; /**< alignment within a region */ + int i_alpha; /**< transparency */ char *psz_text; /**< text string comprising this region */ char *psz_html; /**< HTML version of subtitle (NULL = use psz_text) */ - text_style_t *p_style; /* a description of the text style formatting */ + text_style_t *p_style; /**< a description of the text style formatting */ subpicture_region_t *p_next; /**< next region in the list */ subpicture_region_t *p_cache; /**< modified version of this region */ diff --git a/modules/video_filter/Modules.am b/modules/video_filter/Modules.am index fb3c14ce07..0907700df0 100644 --- a/modules/video_filter/Modules.am +++ b/modules/video_filter/Modules.am @@ -36,4 +36,5 @@ SOURCES_gaussianblur = gaussianblur.c SOURCES_grain = grain.c SOURCES_seamcarving = seamcarving.c SOURCES_croppadd = croppadd.c +SOURCES_blendbench = blendbench.c noinst_HEADERS = filter_common.h filter_picture.h diff --git a/modules/video_filter/blendbench.c b/modules/video_filter/blendbench.c new file mode 100644 index 0000000000..f21d6f412a --- /dev/null +++ b/modules/video_filter/blendbench.c @@ -0,0 +1,251 @@ +/***************************************************************************** + * blendbench.c : blending benchmark plugin for vlc + ***************************************************************************** + * Copyright (C) 2007 the VideoLAN team + * $Id$ + * + * Author: Søren Bøg + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "vlc_filter.h" +#include "vlc_image.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create( vlc_object_t * ); +static void Destroy( vlc_object_t * ); + +static picture_t *Filter( filter_t *, picture_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ + +#define LOOPS_TEXT N_("Number of time to blend") +#define LOOPS_LONGTEXT N_("The number of time the blend will be performed") + +#define ALPHA_TEXT N_("Alpha of the blended image") +#define ALPHA_LONGTEXT N_("Alpha with which the blend image is blended") + +#define BASE_IMAGE_TEXT N_("Image to be blended onto") +#define BASE_IMAGE_LONGTEXT N_("The image which will be used to blend onto") + +#define BASE_CHROMA_TEXT N_("Chroma for the base image") +#define BASE_CHROMA_LONGTEXT N_("Chroma which the base image will be loaded in") + +#define BLEND_IMAGE_TEXT N_("Image which will be blended.") +#define BLEND_IMAGE_LONGTEXT N_("The image blended onto the base image") + +#define BLEND_CHROMA_TEXT N_("Chroma for the blend image") +#define BLEND_CHROMA_LONGTEXT N_("Chroma which the blend image will be loaded" \ + "in") + +#define CFG_PREFIX "blendbench-" + +vlc_module_begin(); + set_description( _("Blending benchmark filter") ); + set_shortname( _("blendbench" )); + set_category( CAT_VIDEO ); + set_subcategory( SUBCAT_VIDEO_VFILTER ); + set_capability( "video filter2", 0 ); + + set_section( N_("Benchmarking"), NULL ); + add_integer( CFG_PREFIX "loops", 1000, NULL, LOOPS_TEXT, + LOOPS_LONGTEXT, VLC_FALSE ); + add_integer_with_range( CFG_PREFIX "alpha", 128, 0, 255, NULL, ALPHA_TEXT, + ALPHA_LONGTEXT, VLC_FALSE ); + + set_section( N_("Base image"), NULL ); + add_file( CFG_PREFIX "base-image", NULL, NULL, BASE_IMAGE_TEXT, + BASE_IMAGE_LONGTEXT, VLC_FALSE ); + add_string( CFG_PREFIX "base-chroma", "I420", NULL, BASE_CHROMA_TEXT, + BASE_CHROMA_LONGTEXT, VLC_FALSE ); + + set_section( N_("Blend image"), NULL ); + add_file( CFG_PREFIX "blend-image", NULL, NULL, BLEND_IMAGE_TEXT, + BLEND_IMAGE_LONGTEXT, VLC_FALSE ); + add_string( CFG_PREFIX "blend-chroma", "YUVA", NULL, BLEND_CHROMA_TEXT, + BLEND_CHROMA_LONGTEXT, VLC_FALSE ); + + set_callbacks( Create, Destroy ); +vlc_module_end(); + +static const char *ppsz_filter_options[] = { + "loops", "alpha", "base-image", "base-chroma", "blend-image", + "blend-chroma", NULL +}; + +/***************************************************************************** + * filter_sys_t: filter method descriptor + *****************************************************************************/ +struct filter_sys_t +{ + vlc_bool_t b_done; + int i_loops, i_alpha; + + picture_t *p_base_image; + picture_t *p_blend_image; + + vlc_fourcc_t i_base_chroma; + vlc_fourcc_t i_blend_chroma; +}; + +static int LoadImage( vlc_object_t *p_this, picture_t **pp_pic, + vlc_fourcc_t i_chroma, char *psz_file, const char *psz_name ) +{ + image_handler_t *p_image; + video_format_t fmt_in, fmt_out; + + memset( &fmt_in, 0, sizeof(video_format_t) ); + memset( &fmt_out, 0, sizeof(video_format_t) ); + + fmt_out.i_chroma = i_chroma; + p_image = image_HandlerCreate( p_this ); + *pp_pic = image_ReadUrl( p_image, psz_file, &fmt_in, &fmt_out ); + image_HandlerDelete( p_image ); + + if( *pp_pic == NULL ) { + msg_Err( p_this, "Unable to load %s image", psz_name ); + return VLC_EGENERIC; + } + + msg_Dbg( p_this, "%s image has dim %d x %d (Y plane)", psz_name, + (*pp_pic)->p[Y_PLANE].i_visible_pitch, + (*pp_pic)->p[Y_PLANE].i_visible_lines ); + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Create: allocates video thread output method + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + filter_t *p_filter = (filter_t *)p_this; + filter_sys_t *p_sys; + char *psz_temp; + + /* Allocate structure */ + p_filter->p_sys = malloc( sizeof( filter_sys_t ) ); + if( p_filter->p_sys == NULL ) + { + msg_Err( p_filter, "out of memory" ); + return VLC_ENOMEM; + } + p_sys = p_filter->p_sys; + p_sys->b_done = VLC_FALSE; + + p_filter->pf_video_filter = Filter; + + /* needed to get options passed in transcode using the + * adjust{name=value} syntax */ + config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options, + p_filter->p_cfg ); + + p_sys->i_loops = var_CreateGetIntegerCommand( p_filter, + CFG_PREFIX "loops" ); + p_sys->i_alpha = var_CreateGetIntegerCommand( p_filter, + CFG_PREFIX "alpha" ); + + psz_temp = var_CreateGetStringCommand( p_filter, CFG_PREFIX "base-chroma" ); + p_sys->i_base_chroma = VLC_FOURCC( psz_temp[0], psz_temp[1], + psz_temp[2], psz_temp[3] ); + LoadImage( p_this, &p_sys->p_base_image, p_sys->i_base_chroma, + var_CreateGetStringCommand( p_filter, CFG_PREFIX "base-image" ), + "Base" ); + + psz_temp = var_CreateGetStringCommand( p_filter, + CFG_PREFIX "blend-chroma" ); + p_sys->i_blend_chroma = VLC_FOURCC( psz_temp[0], psz_temp[1], + psz_temp[2], psz_temp[3] ); + LoadImage( p_this, &p_sys->p_blend_image, p_sys->i_blend_chroma, + var_CreateGetStringCommand( p_filter, CFG_PREFIX "blend-image" ), + "Blend" ); + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Destroy: destroy video thread output method + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + filter_t *p_filter = (filter_t *)p_this; + filter_sys_t *p_sys = p_filter->p_sys; + + p_sys->p_base_image->pf_release( p_sys->p_base_image ); + p_sys->p_blend_image->pf_release( p_sys->p_blend_image ); +} + +/***************************************************************************** + * Render: displays previously rendered output + *****************************************************************************/ +static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) +{ + filter_sys_t *p_sys = p_filter->p_sys; + + if( p_sys->b_done ) + { + return p_pic; + } + + filter_t *p_blend; + + p_blend = vlc_object_create( p_filter, VLC_OBJECT_FILTER ); + vlc_object_attach( p_blend, p_filter ); + p_blend->fmt_out.video = p_sys->p_base_image->format; + p_blend->fmt_in.video = p_sys->p_blend_image->format; + p_blend->p_module = module_Need( p_blend, "video blending", 0, 0 ); + + mtime_t time = mdate(); + for( int i_iter = 0; i_iter < p_sys->i_loops; ++i_iter ) + { + p_blend->pf_video_blend( p_blend, p_sys->p_base_image, + p_sys->p_base_image, p_sys->p_blend_image, 0, + 0, p_sys->i_alpha ); + } + time = mdate() - time; + + msg_Info( p_filter, "Blended %d images in %f sec.", p_sys->i_loops, + time / 1000000.0f ); + msg_Info( p_filter, "Speed is: %f images/second, %f pixels/second", + (float) p_sys->i_loops / time * 1000000, + (float) p_sys->i_loops / time * 1000000 * + p_sys->p_blend_image->p[Y_PLANE].i_visible_pitch * + p_sys->p_blend_image->p[Y_PLANE].i_visible_lines ); + + module_Unneed( p_blend, p_blend->p_module ); + + vlc_object_detach( p_blend ); + vlc_object_release( p_blend ); + + p_sys->b_done = VLC_TRUE; + return p_pic; +} diff --git a/modules/video_filter/dynamicoverlay/Modules.am b/modules/video_filter/dynamicoverlay/Modules.am new file mode 100644 index 0000000000..5f645e46a8 --- /dev/null +++ b/modules/video_filter/dynamicoverlay/Modules.am @@ -0,0 +1,2 @@ +SOURCES_dynamicoverlay = dynamicoverlay_buffer.c dynamicoverlay_queue.c dynamicoverlay_list.c dynamicoverlay_commands.c dynamicoverlay.c +noinst_HEADERS = dynamicoverlay.h diff --git a/modules/video_filter/dynamicoverlay/dynamicoverlay.c b/modules/video_filter/dynamicoverlay/dynamicoverlay.c new file mode 100644 index 0000000000..cee5c5c416 --- /dev/null +++ b/modules/video_filter/dynamicoverlay/dynamicoverlay.c @@ -0,0 +1,421 @@ +/***************************************************************************** + * dynamicoverlay.c : dynamic overlay plugin for vlc + ***************************************************************************** + * Copyright (C) 2007 the VideoLAN team + * $Id$ + * + * Author: Søren Bøg + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "dynamicoverlay.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create( vlc_object_t * ); +static void Destroy( vlc_object_t * ); +static subpicture_t *Filter( filter_t *, mtime_t ); + +static int AdjustCallback( vlc_object_t *p_this, char const *psz_var, + vlc_value_t oldval, vlc_value_t newval, + void *p_data ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ + +#define INPUT_TEXT N_("Input FIFO") +#define INPUT_LONGTEXT N_("FIFO which will be read for commands") + +#define OUTPUT_TEXT N_("Output FIFO") +#define OUTPUT_LONGTEXT N_("FIFO which will be written to for responses") + +vlc_module_begin(); + set_description( _("Dynamic video overlay") ); + set_shortname( _("Overlay" )); + set_category( CAT_VIDEO ); + set_subcategory( SUBCAT_VIDEO_VFILTER ); + set_capability( "sub filter", 0 ); + + add_file( "overlay-input", NULL, NULL, INPUT_TEXT, INPUT_LONGTEXT, + VLC_FALSE ); + add_file( "overlay-output", NULL, NULL, OUTPUT_TEXT, OUTPUT_LONGTEXT, + VLC_FALSE ); + + add_shortcut( "overlay" ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +static const char *ppsz_filter_options[] = { + "input", "output", NULL +}; + +/***************************************************************************** + * Create: allocates adjust video thread output method + ***************************************************************************** + * This function allocates and initializes a adjust vout method. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + filter_t *p_filter = (filter_t *)p_this; + filter_sys_t *p_sys; + + /* Allocate structure */ + p_filter->p_sys = malloc( sizeof( filter_sys_t ) ); + if( p_filter->p_sys == NULL ) + { + msg_Err( p_filter, "out of memory" ); + return VLC_ENOMEM; + } + p_sys = p_filter->p_sys; + + BufferInit( &p_sys->input ); + BufferInit( &p_sys->output ); + QueueInit( &p_sys->atomic ); + QueueInit( &p_sys->pending ); + QueueInit( &p_sys->processed ); + ListInit( &p_sys->overlays ); + + p_sys->i_inputfd = -1; + p_sys->i_outputfd = -1; + p_sys->b_updated = VLC_TRUE; + p_sys->b_atomic = VLC_FALSE; + + p_filter->pf_sub_filter = Filter; + + config_ChainParse( p_filter, "overlay-", ppsz_filter_options, + p_filter->p_cfg ); + + p_sys->psz_inputfile = var_CreateGetStringCommand( p_filter, + "overlay-input" ); + p_sys->psz_outputfile = var_CreateGetStringCommand( p_filter, + "overlay-output" ); + + var_AddCallback( p_filter, "overlay-input", AdjustCallback, p_sys ); + var_AddCallback( p_filter, "overlay-output", AdjustCallback, p_sys ); + + RegisterCommand( p_filter ); + return VLC_SUCCESS; +} + +/***************************************************************************** + * Destroy: destroy adjust video thread output method + ***************************************************************************** + * Terminate an output method created by adjustCreateOutputMethod + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + filter_t *p_filter = (filter_t *)p_this; + + BufferDestroy( &p_filter->p_sys->input ); + BufferDestroy( &p_filter->p_sys->output ); + QueueDestroy( &p_filter->p_sys->atomic ); + QueueDestroy( &p_filter->p_sys->pending ); + QueueDestroy( &p_filter->p_sys->processed ); + ListDestroy( &p_filter->p_sys->overlays ); + UnregisterCommand( p_filter ); + + free( p_filter->p_sys->psz_inputfile ); + free( p_filter->p_sys->psz_outputfile ); + free( p_filter->p_sys ); +} + +/***************************************************************************** + * Render: displays previously rendered output + ***************************************************************************** + * This function send the currently rendered image to adjust modified image, + * waits until it is displayed and switch the two rendering buffers, preparing + * next frame. + *****************************************************************************/ +static subpicture_t *Filter( filter_t *p_filter, mtime_t date ) +{ + filter_sys_t *p_sys = p_filter->p_sys; + + /* We might need to open these at any time. */ + if( p_sys->i_inputfd == -1 ) + { + p_sys->i_inputfd = open( p_sys->psz_inputfile, O_RDONLY | O_NONBLOCK ); + if( p_sys->i_inputfd == -1 ) + { + msg_Warn( p_filter, "Failed to grab input file: %s (%s)", + p_sys->psz_inputfile, strerror( errno ) ); + } + else + { + msg_Info( p_filter, "Grabbed input file: %s", + p_sys->psz_inputfile ); + } + } + + if( p_sys->i_outputfd == -1 ) + { + p_sys->i_outputfd = open( p_sys->psz_outputfile, + O_WRONLY | O_NONBLOCK ); + if( p_sys->i_outputfd == -1 ) + { + if( errno != ENXIO ) + { + msg_Warn( p_filter, "Failed to grab output file: %s (%s)", + p_sys->psz_outputfile, strerror( errno ) ); + } + } + else + { + msg_Info( p_filter, "Grabbed output file: %s", + p_sys->psz_outputfile ); + } + } + + /* Read any waiting commands */ + if( p_sys->i_inputfd != -1 ) + { + char p_buffer[1024]; + ssize_t i_len = read( p_sys->i_inputfd, p_buffer, 1024 ); + if( i_len == -1 ) + { + /* We hit an error */ + if( errno != EAGAIN ) + { + msg_Warn( p_filter, "Error on input file: %s", + strerror( errno ) ); + close( p_sys->i_inputfd ); + p_sys->i_inputfd = -1; + } + } + else if( i_len == 0 ) + { + /* We hit the end-of-file */ + } + else + { + BufferAdd( &p_sys->input, p_buffer, i_len ); + } + } + + /* Parse any complete commands */ + char *p_end, *p_cmd; + while( ( p_end = memchr( p_sys->input.p_begin, '\n', + p_sys->input.i_length ) ) ) + { + commanddesc_t *p_cur = NULL; + vlc_bool_t b_found = VLC_FALSE; + size_t i_index = 0; + + *p_end = '\0'; + p_cmd = BufferGetToken( &p_sys->input ); + + msg_Info( p_filter, "Search command: %s", p_cmd ); + for( i_index = 0; i_index < p_sys->i_commands; i_index++ ) + { + p_cur = p_sys->pp_commands[i_index]; + if( !strncmp( p_cur->psz_command, p_cmd, strlen(p_cur->psz_command) ) ) + { + p_cmd[strlen(p_cur->psz_command)] = '\0'; + b_found = VLC_TRUE; + break; + } + } + + if( !b_found ) + { + /* No matching command */ + msg_Err( p_filter, "Got invalid command: %s", p_cmd ); + BufferPrintf( &p_sys->output, "FAILURE: %d Invalid Command\n", VLC_EGENERIC ); + } + else + { + msg_Info( p_filter, "Got valid command: %s", p_cmd ); + + command_t *p_cmddesc = malloc( sizeof( command_t ) ); + if( !p_cmddesc ) + return NULL; + + p_cmd = p_cmd + strlen(p_cur->psz_command) +1; + p_cmddesc->p_command = p_cur; + p_cmddesc->p_command->pf_parser( p_cmd, p_end, + &p_cmddesc->params ); + + if( ( p_cmddesc->p_command->b_atomic == VLC_TRUE ) && + ( p_sys->b_atomic == VLC_TRUE ) ) + QueueEnqueue( &p_sys->atomic, p_cmddesc ); + else + QueueEnqueue( &p_sys->pending, p_cmddesc ); + } + + BufferDel( &p_sys->input, p_end - p_sys->input.p_begin + 1 ); + } + + /* Process any pending commands */ + command_t *p_command = NULL; + while( (p_command = QueueDequeue( &p_sys->pending )) ) + { + p_command->i_status = + p_command->p_command->pf_execute( p_filter, &p_command->params, + &p_command->results ); + QueueEnqueue( &p_sys->processed, p_command ); + } + + /* Output any processed commands */ + while( (p_command = QueueDequeue( &p_sys->processed )) ) + { + if( p_command->i_status == VLC_SUCCESS ) + { + const char *psz_success = "SUCCESS:"; + const char *psz_nl = "\n"; + BufferAdd( &p_sys->output, psz_success, 8 ); + p_command->p_command->pf_unparse( &p_command->results, + &p_sys->output ); + BufferAdd( &p_sys->output, psz_nl, 1 ); + } + else + { + BufferPrintf( &p_sys->output, "FAILURE: %d\n", + p_command->i_status ); + } + } + + /* Try emptying the output buffer */ + if( p_sys->i_outputfd != -1 ) + { + ssize_t i_len = write( p_sys->i_outputfd, p_sys->output.p_begin, + p_sys->output.i_length ); + if( i_len == -1 ) + { + /* We hit an error */ + if( errno != EAGAIN ) + { + msg_Warn( p_filter, "Error on output file: %s", + strerror( errno ) ); + close( p_sys->i_outputfd ); + p_sys->i_outputfd = -1; + } + } + else + { + BufferDel( &p_sys->output, i_len ); + } + } + + if( p_sys->b_updated == VLC_FALSE ) + return NULL; + + subpicture_t *p_spu = NULL; + overlay_t *p_overlay = NULL; + + p_spu = p_filter->pf_sub_buffer_new( p_filter ); + if( !p_spu ) + { + msg_Err( p_filter, "cannot allocate subpicture" ); + return NULL; + } + + p_spu->i_flags = OSD_ALIGN_LEFT | OSD_ALIGN_TOP; + p_spu->i_x = 0; + p_spu->i_y = 0; + p_spu->b_absolute = VLC_TRUE; + p_spu->i_start = date; + p_spu->i_stop = 0; + p_spu->b_ephemer = VLC_TRUE; + + subpicture_region_t **pp_region = &p_spu->p_region; + while( (p_overlay = ListWalk( &p_sys->overlays )) ) + { + msg_Dbg( p_filter, "Displaying overlay: %4.4s, %d, %d, %d", + (char*)&p_overlay->format.i_chroma, p_overlay->i_x, p_overlay->i_y, + p_overlay->i_alpha ); + + if( p_overlay->format.i_chroma == VLC_FOURCC('T','E','X','T') ) + { + *pp_region = p_spu->pf_create_region( VLC_OBJECT(p_filter), + &p_overlay->format ); + if( !*pp_region ) + break; + (*pp_region)->psz_text = strdup( p_overlay->data.p_text ); + (*pp_region)->p_style = malloc( sizeof(struct text_style_t) ); + if( !(*pp_region)->p_style ) + { + p_spu->pf_destroy_region( VLC_OBJECT(p_filter), (*pp_region) ); + *pp_region = NULL; + break; + } + p_filter->p_libvlc->pf_memcpy( (*pp_region)->p_style, + &p_overlay->fontstyle, + sizeof(struct text_style_t) ); + } + else + { + picture_t clone; + if( vout_AllocatePicture( p_filter, &clone, + p_overlay->format.i_chroma, + p_overlay->format.i_width, + p_overlay->format.i_height, + p_overlay->format.i_aspect ) ) + { + msg_Err( p_filter, "cannot allocate picture" ); + continue; + } + vout_CopyPicture( p_filter, &clone, p_overlay->data.p_pic ); + *pp_region = p_spu->pf_make_region( VLC_OBJECT(p_filter), + &p_overlay->format, + &clone ); + if( !*pp_region ) + { + msg_Err( p_filter, "cannot allocate subpicture region" ); + continue; + } + } + (*pp_region)->i_x = p_overlay->i_x; + (*pp_region)->i_y = p_overlay->i_y; + (*pp_region)->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP; + (*pp_region)->i_alpha = p_overlay->i_alpha; + pp_region = &(*pp_region)->p_next; + } + + p_sys->b_updated = VLC_FALSE; + return p_spu; +} + +static int AdjustCallback( vlc_object_t *p_this, char const *psz_var, + vlc_value_t oldval, vlc_value_t newval, + void *p_data ) +{ + filter_sys_t *p_sys = (filter_sys_t *)p_data; + VLC_UNUSED(p_this); VLC_UNUSED(oldval); + + if( !strncmp( psz_var, "overlay-input", 13 ) ) + p_sys->psz_inputfile = newval.psz_string; + else if( !strncmp( psz_var, "overlay-output", 14 ) ) + p_sys->psz_outputfile = newval.psz_string; + + return VLC_EGENERIC; +} diff --git a/modules/video_filter/dynamicoverlay/dynamicoverlay.h b/modules/video_filter/dynamicoverlay/dynamicoverlay.h new file mode 100644 index 0000000000..db8cac59d6 --- /dev/null +++ b/modules/video_filter/dynamicoverlay/dynamicoverlay.h @@ -0,0 +1,170 @@ +/***************************************************************************** + * dynamicoverlay.h : dynamic overlay plugin for vlc + ***************************************************************************** + * Copyright (C) 2008 the VideoLAN team + * $Id$ + * + * Author: Jean-Paul Saman + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifndef DYNAMIC_OVERLAY_H +#define DYNAMIC_OVERLAY_H 1 + +#include +#include + +/***************************************************************************** + * buffer_t: Command and response buffer + *****************************************************************************/ + +typedef struct buffer_t +{ + size_t i_size; /**< Size of the allocated memory */ + size_t i_length; /**< Length of the stored data */ + + char *p_memory; /**< Start of the allocated memory */ + char *p_begin; /**< Start of the stored data */ +} buffer_t; + +int BufferInit( buffer_t *p_buffer ); +int BufferDestroy( buffer_t *p_buffer ); +int BufferAdd( buffer_t *p_buffer, const char *p_data, size_t i_len ); +int BufferPrintf( buffer_t *p_buffer, const char *p_fmt, ... ); +int BufferDel( buffer_t *p_buffer, int i_len ); +char *BufferGetToken( buffer_t *p_buffer ); + +/***************************************************************************** + * Command structures + *****************************************************************************/ + +/** struct commandparams_t - command params structure */ +typedef struct commandparams_t +{ + int32_t i_id; /*< overlay id */ + int32_t i_shmid; /*< shared memory identifier */ + + vlc_fourcc_t fourcc;/*< chroma */ + + int32_t i_x; /*< x position of overlay */ + int32_t i_y; /*< y position of overlay */ + int32_t i_width; /*< width of overlay */ + int32_t i_height; /*< height of overlay */ + + int32_t i_alpha; /*< alpha value of overlay */ + + struct text_style_t fontstyle; /*< text style */ + + vlc_bool_t b_visible; /*< visibility flag of overlay */ +} commandparams_t; + +typedef struct commanddesc_t +{ + const char *psz_command; + vlc_bool_t b_atomic; + int ( *pf_parser ) ( char *psz_command, char *psz_end, + commandparams_t *p_params ); + int ( *pf_execute ) ( filter_t *p_filter, const commandparams_t *p_params, + commandparams_t *p_results ); + int ( *pf_unparse ) ( const commandparams_t *p_results, + buffer_t *p_output ); +} commanddesc_t; + +typedef struct command_t +{ + struct commanddesc_t *p_command; + int i_status; + commandparams_t params; + commandparams_t results; + struct command_t *p_next; +} command_t; + +void RegisterCommand( filter_t *p_filter ); +void UnregisterCommand( filter_t *p_filter ); + +/***************************************************************************** + * queue_t: Command queue + *****************************************************************************/ + +typedef struct queue_t +{ + command_t *p_head; /**< Head (first entry) of the queue */ + command_t *p_tail; /**< Tail (last entry) of the queue */ +} queue_t; + +int QueueInit( queue_t *p_queue ); +int QueueDestroy( queue_t *p_queue ); +int QueueEnqueue( queue_t *p_queue, command_t *p_cmd ); +command_t *QueueDequeue( queue_t *p_queue ); +int QueueTransfer( queue_t *p_sink, queue_t *p_source ); + +/***************************************************************************** + * overlay_t: Overlay descriptor + *****************************************************************************/ + +typedef struct overlay_t +{ + int i_x, i_y; + int i_alpha; + vlc_bool_t b_active; + + video_format_t format; + struct text_style_t fontstyle; + union { + picture_t *p_pic; + char *p_text; + } data; +} overlay_t; + +overlay_t *OverlayCreate( void ); +int OverlayDestroy( overlay_t *p_ovl ); + +/***************************************************************************** + * list_t: Command queue + *****************************************************************************/ + +typedef struct list_t +{ + overlay_t **pp_head, **pp_tail; +} list_t; + +int ListInit( list_t *p_list ); +int ListDestroy( list_t *p_list ); +ssize_t ListAdd( list_t *p_list, overlay_t *p_new ); +int ListRemove( list_t *p_list, size_t i_idx ); +overlay_t *ListGet( list_t *p_list, size_t i_idx ); +overlay_t *ListWalk( list_t *p_list ); + +/***************************************************************************** + * filter_sys_t: adjust filter method descriptor + *****************************************************************************/ + +struct filter_sys_t +{ + buffer_t input, output; + + int i_inputfd, i_outputfd; + char *psz_inputfile, *psz_outputfile; + + commanddesc_t **pp_commands; /* array of commands */ + size_t i_commands; + + vlc_bool_t b_updated, b_atomic; + queue_t atomic, pending, processed; + list_t overlays; +}; + +#endif diff --git a/modules/video_filter/dynamicoverlay/dynamicoverlay_buffer.c b/modules/video_filter/dynamicoverlay/dynamicoverlay_buffer.c new file mode 100644 index 0000000000..ee0e2db477 --- /dev/null +++ b/modules/video_filter/dynamicoverlay/dynamicoverlay_buffer.c @@ -0,0 +1,160 @@ +/***************************************************************************** + * dynamicoverlay_buffer.h : dynamic overlay buffer + ***************************************************************************** + * Copyright (C) 2008 the VideoLAN team + * $Id$ + * + * Author: Søren Bøg + * Jean-Paul Saman + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include + +#include "dynamicoverlay.h" + +/***************************************************************************** + * buffer_t: Command and response buffer + *****************************************************************************/ + +int BufferInit( buffer_t *p_buffer ) +{ + memset( p_buffer, 0, sizeof( buffer_t ) ); + p_buffer->p_memory = NULL; + p_buffer->p_begin = NULL; + + return VLC_SUCCESS; +} + +int BufferDestroy( buffer_t *p_buffer ) +{ + if( p_buffer->p_memory != NULL ) + { + free( p_buffer->p_memory ); + } + p_buffer->p_memory = NULL; + p_buffer->p_begin = NULL; + + return VLC_SUCCESS; +} + +char *BufferGetToken( buffer_t *p_buffer ) +{ + char *p_char = p_buffer->p_begin; + + while( isspace( p_char[0] ) || p_char[0] == '\0' ) + { + if( p_char <= (p_buffer->p_begin + p_buffer->i_length) ) + p_char++; + else + return NULL; + } + return p_char; +} + +int BufferAdd( buffer_t *p_buffer, const char *p_data, size_t i_len ) +{ + if( ( p_buffer->i_size - p_buffer->i_length - + ( p_buffer->p_begin - p_buffer->p_memory ) ) < i_len ) + { + /* We'll have to do some rearranging to fit the new data. */ + if( ( p_buffer->i_size - p_buffer->i_length ) >= i_len ) + { + /* We have room in the current buffer, just need to move it */ + memmove( p_buffer->p_memory, p_buffer->p_begin, + p_buffer->i_length ); + p_buffer->p_begin = p_buffer->p_memory; + } + else + { + // We need a bigger buffer + size_t i_newsize = 1024; + while( i_newsize < p_buffer->i_length + i_len ) + i_newsize *= 2; + /* TODO: Should I handle wrapping here? */ + + /* I'm not using realloc here, as I can avoid a memcpy/memmove in + some (most?) cases, and reset the start of the buffer. */ + char *p_newdata = malloc( i_newsize ); + if( p_newdata == NULL ) + return VLC_ENOMEM; + if( p_buffer->p_begin != NULL ) + { + memcpy( p_newdata, p_buffer->p_begin, p_buffer->i_length ); + free( p_buffer->p_memory ); + } + p_buffer->p_memory = p_buffer->p_begin = p_newdata; + p_buffer->i_size = i_newsize; + } + } + + /* Add the new data to the end of the current */ + memcpy( p_buffer->p_begin + p_buffer->i_length, p_data, i_len ); + p_buffer->i_length += i_len; + return VLC_SUCCESS; +} + +int BufferPrintf( buffer_t *p_buffer, const char *p_fmt, ... ) +{ + int i_len; + int status; + char *psz_data; + + va_list va_list1, va_list2; + va_start( va_list1, p_fmt ); + va_copy( va_list2, va_list1 ); + + i_len = vsnprintf( NULL, 0, p_fmt, va_list1 ); + if( i_len < 0 ) + return VLC_EGENERIC; + va_end( va_list1 ); + + psz_data = malloc( i_len + 1 ); + if( psz_data == NULL ) { + return VLC_ENOMEM; + } + if( vsnprintf( psz_data, i_len + 1, p_fmt, va_list2 ) != i_len ) + { + return VLC_EGENERIC; + } + va_end( va_list2 ); + status = BufferAdd( p_buffer, psz_data, i_len ); + free( psz_data ); + return status; +} + +int BufferDel( buffer_t *p_buffer, int i_len ) +{ + p_buffer->i_length -= i_len; + if( p_buffer->i_length == 0 ) + { + /* No data, we can reset the buffer now. */ + p_buffer->p_begin = p_buffer->p_memory; + } + else + { + p_buffer->p_begin += i_len; + } + return VLC_SUCCESS; +} diff --git a/modules/video_filter/dynamicoverlay/dynamicoverlay_commands.c b/modules/video_filter/dynamicoverlay/dynamicoverlay_commands.c new file mode 100644 index 0000000000..14630fc648 --- /dev/null +++ b/modules/video_filter/dynamicoverlay/dynamicoverlay_commands.c @@ -0,0 +1,932 @@ +/***************************************************************************** + * dynamicoverlay_commands.c : dynamic overlay plugin commands + ***************************************************************************** + * Copyright (C) 2008 the VideoLAN team + * $Id$ + * + * Author: Søren Bøg + * Jean-Paul Saman + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "dynamicoverlay.h" + + +/***************************************************************************** + * overlay_t: Overlay descriptor + *****************************************************************************/ + +overlay_t *OverlayCreate( void ) +{ + overlay_t *p_ovl = malloc( sizeof( overlay_t ) ); + if( p_ovl == NULL ) + return NULL; + memset( p_ovl, 0, sizeof( overlay_t ) ); + + p_ovl->i_x = p_ovl->i_y = 0; + p_ovl->i_alpha = 0xFF; + p_ovl->b_active = VLC_FALSE; + vout_InitFormat( &p_ovl->format, VLC_FOURCC( '\0','\0','\0','\0') , 0, 0, + VOUT_ASPECT_FACTOR ); + memcpy( &p_ovl->fontstyle, &default_text_style, sizeof(struct text_style_t) ); + p_ovl->data.p_text = NULL; + + return p_ovl; +} + +int OverlayDestroy( overlay_t *p_ovl ) +{ + if( p_ovl->data.p_text != NULL ) + free( p_ovl->data.p_text ); + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Command parsers + *****************************************************************************/ +static int skip_space( char **psz_command ) +{ + char *psz_temp = *psz_command; + + while( isspace( *psz_temp ) ) + { + ++psz_temp; + } + if( psz_temp == *psz_command ) + { + return VLC_EGENERIC; + } + *psz_command = psz_temp; + return VLC_SUCCESS; +} + +static int parse_digit( char **psz_command, int32_t *value ) +{ + char *psz_temp; + *value = strtol( *psz_command, &psz_temp, 10 ); + if( psz_temp == *psz_command ) + { + return VLC_EGENERIC; + } + *psz_command = psz_temp; + return VLC_SUCCESS; +} + +static int parse_char( char **psz_command, char **psz_end, + int count, char *psz_value ) +{ + if( *psz_end - *psz_command < count ) + { + return VLC_EGENERIC; + } + memcpy( psz_value, *psz_command, count ); + *psz_command += count; + return VLC_SUCCESS; +} + +static int parser_DataSharedMem( char *psz_command, + char *psz_end, + commandparams_t *p_params ) +{ + /* Parse: 0 128 128 RGBA 9404459 */ + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_id ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_width ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_height ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isascii( *psz_command ) ) + { + if( parse_char( &psz_command, &psz_end, 4, (char*)&p_params->fourcc ) + == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_shmid ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + return VLC_SUCCESS; +} + +static int parser_Id( char *psz_command, char *psz_end, + commandparams_t *p_params ) +{ + (void)(psz_end); + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_id ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + return VLC_SUCCESS; +} + +static int parser_None( char *psz_command, char *psz_end, + commandparams_t *p_params ) +{ + (void)(psz_command); + (void)(psz_end); + (void)(p_params); + return VLC_SUCCESS; +} + +static int parser_SetAlpha( char *psz_command, char *psz_end, + commandparams_t *p_params ) +{ + (void)(psz_end); + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_id ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_alpha ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + return VLC_SUCCESS; +} + +static int parser_SetPosition( char *psz_command, char *psz_end, + commandparams_t *p_params ) +{ + (void)(psz_end); + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_id ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_x ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_y ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + return VLC_SUCCESS; +} + +static int parser_SetTextAlpha( char *psz_command, char *psz_end, + commandparams_t *p_params ) +{ + (void)(psz_end); + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_id ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->fontstyle.i_font_alpha ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + return VLC_SUCCESS; +} + +static int parser_SetTextColor( char *psz_command, char *psz_end, + commandparams_t *p_params ) +{ + int r, g, b; + (void)(psz_end); + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_id ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &r ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &g ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &b ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + p_params->fontstyle.i_font_color = (r<<24) | (g<<16) | (b<<8); + return VLC_SUCCESS; +} + +static int parser_SetTextSize( char *psz_command, char *psz_end, + commandparams_t *p_params ) +{ + (void)(psz_end); + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_id ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->fontstyle.i_font_size ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + return VLC_SUCCESS; +} + +static int parser_SetVisibility( char *psz_command, char *psz_end, + commandparams_t *p_params ) +{ + (void)(psz_end); + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + if( parse_digit( &psz_command, &p_params->i_id ) == VLC_EGENERIC ) + return VLC_EGENERIC; + } + skip_space( &psz_command ); + if( isdigit( *psz_command ) ) + { + int32_t i_vis = 0; + if( parse_digit( &psz_command, &i_vis ) == VLC_EGENERIC ) + return VLC_EGENERIC; + p_params->b_visible = (i_vis == 1) ? VLC_TRUE : VLC_FALSE; + } + return VLC_SUCCESS; +} + +/***************************************************************************** + * Command unparser functions + *****************************************************************************/ + +static int unparse_default( const commandparams_t *p_results, + buffer_t *p_output ) +{ + (void)(p_results); + VLC_UNUSED(p_output); + return VLC_SUCCESS; +} + +static int unparse_GenImage( const commandparams_t *p_results, + buffer_t *p_output ) +{ + int ret = BufferPrintf( p_output, " %d", p_results->i_id ); + if( ret != VLC_SUCCESS ) + return ret; + + return VLC_SUCCESS; +} + +static int unparse_GetAlpha( const commandparams_t *p_results, + buffer_t *p_output ) +{ + int ret = BufferPrintf( p_output, " %d", p_results->i_alpha ); + if( ret != VLC_SUCCESS ) + return ret; + + return VLC_SUCCESS; +} + +static int unparse_GetPosition( const commandparams_t *p_results, + buffer_t *p_output ) +{ + int ret = BufferPrintf( p_output, " %d", p_results->i_x ); + if( ret != VLC_SUCCESS ) + return ret; + + ret = BufferPrintf( p_output, " %d", p_results->i_y ); + if( ret != VLC_SUCCESS ) + return ret; + + return VLC_SUCCESS; +} + +static int unparse_GetTextAlpha( const commandparams_t *p_results, + buffer_t *p_output ) +{ + int ret = BufferPrintf( p_output, " %d", p_results->fontstyle.i_font_alpha ); + if( ret != VLC_SUCCESS ) + return ret; + + return VLC_SUCCESS; +} + +static int unparse_GetTextColor( const commandparams_t *p_results, + buffer_t *p_output ) +{ + int ret = BufferPrintf( p_output, " %d", (p_results->fontstyle.i_font_color & 0xff0000)>>24 ); + if( ret != VLC_SUCCESS ) + return ret; + + ret = BufferPrintf( p_output, " %d", (p_results->fontstyle.i_font_color & 0x00ff00)>>16 ); + if( ret != VLC_SUCCESS ) + return ret; + + ret = BufferPrintf( p_output, " %d", (p_results->fontstyle.i_font_color & 0x0000ff)>>8 ); + if( ret != VLC_SUCCESS ) + return ret; + + return VLC_SUCCESS; +} + +static int unparse_GetTextSize( const commandparams_t *p_results, + buffer_t *p_output ) +{ + int ret = BufferPrintf( p_output, " %d", p_results->fontstyle.i_font_size ); + if( ret != VLC_SUCCESS ) + return ret; + + return VLC_SUCCESS; +} + +static int unparse_GetVisibility( const commandparams_t *p_results, + buffer_t *p_output ) +{ + int ret = BufferPrintf( p_output, " %d", (p_results->b_visible ? 1 : 0) ); + if( ret != VLC_SUCCESS ) { + return ret; + } + return VLC_SUCCESS; +} + +/***************************************************************************** + * Command functions + *****************************************************************************/ +static int exec_DataSharedMem( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + struct shmid_ds shminfo; + overlay_t *p_ovl; + size_t i_size; + + (void)(p_results); + + p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + { + msg_Err( p_filter, "Invalid overlay: %d", p_params->i_id ); + return VLC_EGENERIC; + } + + if( shmctl( p_params->i_shmid, IPC_STAT, &shminfo ) == -1 ) + { + msg_Err( p_filter, "Unable to access shared memory" ); + return VLC_EGENERIC; + } + i_size = shminfo.shm_segsz; + + if( p_params->fourcc == VLC_FOURCC('T','E','X','T') ) + { + char *p_data; + + if( (p_params->i_height != 1) || (p_params->i_width < 1) ) + { + msg_Err( p_filter, + "Invalid width and/or height. when specifing text height " + "must be 1 and width the number of bytes in the string, " + "including the null terminator" ); + return VLC_EGENERIC; + } + + if( (size_t)p_params->i_width > i_size ) + { + msg_Err( p_filter, + "Insufficient data in shared memory. need %d, got %d", + p_params->i_width, i_size ); + return VLC_EGENERIC; + } + + p_ovl->data.p_text = malloc( p_params->i_width ); + if( p_ovl->data.p_text == NULL ) + { + msg_Err( p_filter, "Unable to allocate string storage" ); + return VLC_ENOMEM; + } + + vout_InitFormat( &p_ovl->format, VLC_FOURCC('T','E','X','T'), + 0, 0, 0 ); + + p_data = shmat( p_params->i_shmid, NULL, SHM_RDONLY ); + if( p_data == NULL ) + { + msg_Err( p_filter, "Unable to attach to shared memory" ); + free( p_ovl->data.p_text ); + p_ovl->data.p_text = NULL; + return VLC_ENOMEM; + } + + memcpy( p_ovl->data.p_text, p_data, p_params->i_width ); + + shmdt( p_data ); + } + else + { + uint8_t *p_data, *p_in; + size_t i_neededsize = 0; + + p_ovl->data.p_pic = malloc( sizeof( picture_t ) ); + if( p_ovl->data.p_pic == NULL ) + { + msg_Err( p_filter, "Unable to allocate picture structure" ); + return VLC_ENOMEM; + } + + vout_InitFormat( &p_ovl->format, p_params->fourcc, + p_params->i_width, p_params->i_height, + VOUT_ASPECT_FACTOR ); + if( vout_AllocatePicture( p_filter, p_ovl->data.p_pic, + p_ovl->format.i_chroma, p_params->i_width, + p_params->i_height, p_ovl->format.i_aspect ) ) + { + msg_Err( p_filter, "Unable to allocate picture" ); + free( p_ovl->data.p_pic ); + p_ovl->data.p_pic = NULL; + return VLC_ENOMEM; + } + + for( size_t i_plane = 0; i_plane < (size_t)p_ovl->data.p_pic->i_planes; + ++i_plane ) + { + i_neededsize += p_ovl->data.p_pic->p[i_plane].i_visible_lines * + p_ovl->data.p_pic->p[i_plane].i_visible_pitch; + } + + if( i_neededsize > i_size ) + { + msg_Err( p_filter, + "Insufficient data in shared memory. need %d, got %d", + i_neededsize, i_size ); + p_ovl->data.p_pic->pf_release( p_ovl->data.p_pic ); + free( p_ovl->data.p_pic ); + p_ovl->data.p_pic = NULL; + return VLC_EGENERIC; + } + + p_data = shmat( p_params->i_shmid, NULL, SHM_RDONLY ); + if( p_data == NULL ) + { + msg_Err( p_filter, "Unable to attach to shared memory" ); + p_ovl->data.p_pic->pf_release( p_ovl->data.p_pic ); + free( p_ovl->data.p_pic ); + p_ovl->data.p_pic = NULL; + return VLC_ENOMEM; + } + + p_in = p_data; + for( size_t i_plane = 0; i_plane < (size_t)p_ovl->data.p_pic->i_planes; + ++i_plane ) + { + uint8_t *p_out = p_ovl->data.p_pic->p[i_plane].p_pixels; + for( size_t i_line = 0; + i_line < (size_t)p_ovl->data.p_pic->p[i_plane].i_visible_lines; + ++i_line ) + { + p_filter->p_libvlc->pf_memcpy( p_out, p_in, + p_ovl->data.p_pic->p[i_plane].i_visible_pitch ); + p_out += p_ovl->data.p_pic->p[i_plane].i_pitch; + p_in += p_ovl->data.p_pic->p[i_plane].i_visible_pitch; + } + } + shmdt( p_data ); + } + + p_sys->b_updated = p_ovl->b_active; + + return VLC_SUCCESS; +} + +static int exec_DeleteImage( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + (void)(p_results); + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + p_sys->b_updated = VLC_TRUE; + + return ListRemove( &p_sys->overlays, p_params->i_id ); +} + +static int exec_EndAtomic( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + (void)(p_params); + (void)(p_results); + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + QueueTransfer( &p_sys->pending, &p_sys->atomic ); + p_sys->b_atomic = VLC_FALSE; + return VLC_SUCCESS; +} + +static int exec_GenImage( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + (void)(p_params); + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + + overlay_t *p_ovl = OverlayCreate(); + if( p_ovl == NULL ) + return VLC_ENOMEM; + + ssize_t i_idx = ListAdd( &p_sys->overlays, p_ovl ); + if( i_idx < 0 ) + return i_idx; + + p_results->i_id = i_idx; + return VLC_SUCCESS; +} + +static int exec_GetAlpha( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + return VLC_EGENERIC; + + p_results->i_alpha = p_ovl->i_alpha; + return VLC_SUCCESS; +} + +static int exec_GetPosition( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + return VLC_EGENERIC; + + p_results->i_x = p_ovl->i_x; + p_results->i_y = p_ovl->i_y; + return VLC_SUCCESS; +} + +static int exec_GetTextAlpha( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + return VLC_EGENERIC; + + p_results->fontstyle.i_font_alpha = p_ovl->fontstyle.i_font_alpha; + return VLC_SUCCESS; +} + +static int exec_GetTextColor( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + return VLC_EGENERIC; + + p_results->fontstyle.i_font_color = p_ovl->fontstyle.i_font_color; + return VLC_SUCCESS; +} + +static int exec_GetTextSize( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + return VLC_EGENERIC; + + p_results->fontstyle.i_font_size = p_ovl->fontstyle.i_font_size; + return VLC_SUCCESS; +} + +static int exec_GetVisibility( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + + overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + return VLC_EGENERIC; + + p_results->b_visible = ( p_ovl->b_active == VLC_TRUE ) ? 1 : 0; + return VLC_SUCCESS; +} + +static int exec_SetAlpha( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + (void)(p_results); + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + + overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + return VLC_EGENERIC; + + p_ovl->i_alpha = p_params->i_alpha; + p_sys->b_updated = p_ovl->b_active; + return VLC_SUCCESS; +} + +static int exec_SetPosition( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + (void)(p_results); + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + + overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + return VLC_EGENERIC; + + p_ovl->i_x = p_params->i_x; + p_ovl->i_y = p_params->i_y; + + p_sys->b_updated = p_ovl->b_active; + return VLC_SUCCESS; +} + +static int exec_SetTextAlpha( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + (void)(p_results); + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + + overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + return VLC_EGENERIC; + + p_ovl->fontstyle.i_font_alpha = p_params->fontstyle.i_font_alpha; + p_sys->b_updated = p_ovl->b_active; + return VLC_SUCCESS; +} + +static int exec_SetTextColor( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + (void)(p_results); + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + + overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + return VLC_EGENERIC; + + p_ovl->fontstyle.i_font_color = p_params->fontstyle.i_font_color; + p_sys->b_updated = p_ovl->b_active; + return VLC_SUCCESS; +} + +static int exec_SetTextSize( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + (void)(p_results); + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + + overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + return VLC_EGENERIC; + + p_ovl->fontstyle.i_font_size = p_params->fontstyle.i_font_size; + p_sys->b_updated = p_ovl->b_active; + return VLC_SUCCESS; +} + +static int exec_SetVisibility( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + (void)(p_results); + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + + overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id ); + if( p_ovl == NULL ) + return VLC_EGENERIC; + + p_ovl->b_active = p_params->b_visible;// ? VLC_FALSE : VLC_TRUE; + p_sys->b_updated = VLC_TRUE; + return VLC_SUCCESS; +} + +static int exec_StartAtomic( filter_t *p_filter, + const commandparams_t *p_params, + commandparams_t *p_results ) +{ + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + (void)(p_params); + (void)(p_results); + + p_sys->b_atomic = VLC_TRUE; + return VLC_SUCCESS; +} + +/***************************************************************************** + * Command functions + *****************************************************************************/ +static commanddesc_t p_commands[] = +{ + { .psz_command = "DataSharedMem", + .b_atomic = VLC_TRUE, + .pf_parser = parser_DataSharedMem, + .pf_execute = exec_DataSharedMem, + .pf_unparse = unparse_default, + }, + { .psz_command = "DeleteImage", + .b_atomic = VLC_TRUE, + .pf_parser = parser_Id, + .pf_execute = exec_DeleteImage, + .pf_unparse = unparse_default, + }, + { .psz_command = "EndAtomic", + .b_atomic = VLC_FALSE, + .pf_parser = parser_None, + .pf_execute = exec_EndAtomic, + .pf_unparse = unparse_default, + }, + { .psz_command = "GenImage", + .b_atomic = VLC_FALSE, + .pf_parser = parser_None, + .pf_execute = exec_GenImage, + .pf_unparse = unparse_GenImage, + }, + { .psz_command = "GetAlpha", + .b_atomic = VLC_FALSE, + .pf_parser = parser_Id, + .pf_execute = exec_GetAlpha, + .pf_unparse = unparse_GetAlpha, + }, + { .psz_command = "GetPosition", + .b_atomic = VLC_FALSE, + .pf_parser = parser_Id, + .pf_execute = exec_GetPosition, + .pf_unparse = unparse_GetPosition, + }, + { .psz_command = "GetTextAlpha", + .b_atomic = VLC_FALSE, + .pf_parser = parser_Id, + .pf_execute = exec_GetTextAlpha, + .pf_unparse = unparse_GetTextAlpha, + }, + { .psz_command = "GetTextColor", + .b_atomic = VLC_FALSE, + .pf_parser = parser_Id, + .pf_execute = exec_GetTextColor, + .pf_unparse = unparse_GetTextColor, + }, + { .psz_command = "GetTextSize", + .b_atomic = VLC_TRUE, + .pf_parser = parser_Id, + .pf_execute = exec_GetTextSize, + .pf_unparse = unparse_GetTextSize, + }, + { .psz_command = "GetVisibility", + .b_atomic = VLC_FALSE, + .pf_parser = parser_Id, + .pf_execute = exec_GetVisibility, + .pf_unparse = unparse_GetVisibility, + }, + { .psz_command = "SetAlpha", + .b_atomic = VLC_TRUE, + .pf_parser = parser_SetAlpha, + .pf_execute = exec_SetAlpha, + .pf_unparse = unparse_default, + }, + { .psz_command = "SetPosition", + .b_atomic = VLC_TRUE, + .pf_parser = parser_SetPosition, + .pf_execute = exec_SetPosition, + .pf_unparse = unparse_default, + }, + { .psz_command = "SetTextAlpha", + .b_atomic = VLC_TRUE, + .pf_parser = parser_SetTextAlpha, + .pf_execute = exec_SetTextAlpha, + .pf_unparse = unparse_default, + }, + { .psz_command = "SetTextColor", + .b_atomic = VLC_TRUE, + .pf_parser = parser_SetTextColor, + .pf_execute = exec_SetTextColor, + .pf_unparse = unparse_default, + }, + { .psz_command = "SetTextSize", + .b_atomic = VLC_TRUE, + .pf_parser = parser_SetTextSize, + .pf_execute = exec_SetTextSize, + .pf_unparse = unparse_default, + }, + { .psz_command = "SetVisibility", + .b_atomic = VLC_TRUE, + .pf_parser = parser_SetVisibility, + .pf_execute = exec_SetVisibility, + .pf_unparse = unparse_default, + }, + { .psz_command = "StartAtomic", + .b_atomic = VLC_TRUE, + .pf_parser = parser_None, + .pf_execute = exec_StartAtomic, + .pf_unparse = unparse_default, + } +}; + +void RegisterCommand( filter_t *p_filter ) +{ + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + size_t i_index = 0; + + p_sys->i_commands = ARRAY_SIZE(p_commands); + p_sys->pp_commands = (commanddesc_t **) calloc( p_sys->i_commands, sizeof(commanddesc_t*) ); + if( !p_sys->pp_commands ) return; + for( i_index = 0; i_index < p_sys->i_commands; i_index ++ ) + { + p_sys->pp_commands[i_index] = (commanddesc_t *) malloc( sizeof(commanddesc_t) ); + if( !p_sys->pp_commands[i_index] ) return; + p_sys->pp_commands[i_index]->psz_command = strdup( p_commands[i_index].psz_command ); + p_sys->pp_commands[i_index]->b_atomic = p_commands[i_index].b_atomic; + p_sys->pp_commands[i_index]->pf_parser = p_commands[i_index].pf_parser; + p_sys->pp_commands[i_index]->pf_execute = p_commands[i_index].pf_execute; + p_sys->pp_commands[i_index]->pf_unparse = p_commands[i_index].pf_unparse; + } + + msg_Dbg( p_filter, "%d commands are available", p_sys->i_commands ); + for( size_t i_index = 0; i_index < p_sys->i_commands; i_index++ ) + msg_Dbg( p_filter, " %s", p_sys->pp_commands[i_index]->psz_command ); +} + +void UnregisterCommand( filter_t *p_filter ) +{ + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + size_t i_index = 0; + + for( i_index = 0; i_index < p_sys->i_commands; i_index++ ) + { + free( p_sys->pp_commands[i_index]->psz_command ); + free( p_sys->pp_commands[i_index] ); + } + free( p_sys->pp_commands ); + p_sys->pp_commands = NULL; + p_sys->i_commands = 0; +} diff --git a/modules/video_filter/dynamicoverlay/dynamicoverlay_list.c b/modules/video_filter/dynamicoverlay/dynamicoverlay_list.c new file mode 100644 index 0000000000..06924fbb62 --- /dev/null +++ b/modules/video_filter/dynamicoverlay/dynamicoverlay_list.c @@ -0,0 +1,143 @@ +/***************************************************************************** + * dynamicoverlay_list.h : dynamic overlay list + ***************************************************************************** + * Copyright (C) 2008 the VideoLAN team + * $Id$ + * + * Author: Søren Bøg + * Jean-Paul Saman + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#include "dynamicoverlay.h" + +/***************************************************************************** + * list_t: Command queue + *****************************************************************************/ + +int ListInit( list_t *p_list ) +{ + p_list->pp_head = malloc( 16 * sizeof( overlay_t * ) ); + if( p_list->pp_head == NULL ) + return VLC_ENOMEM; + + p_list->pp_tail = p_list->pp_head + 16; + memset( p_list->pp_head, 0, 16 * sizeof( overlay_t * ) ); + + return VLC_SUCCESS; +} + +int ListDestroy( list_t *p_list ) +{ + for( overlay_t **pp_cur = p_list->pp_head; + pp_cur < p_list->pp_tail; + ++pp_cur ) + { + if( *pp_cur != NULL ) + { + OverlayDestroy( *pp_cur ); + free( *pp_cur ); + } + } + free( p_list->pp_head ); + + return VLC_SUCCESS; +} + +ssize_t ListAdd( list_t *p_list, overlay_t *p_new ) +{ + /* Find an available slot */ + for( overlay_t **pp_cur = p_list->pp_head; + pp_cur < p_list->pp_tail; + ++pp_cur ) + { + if( *pp_cur == NULL ) + { + *pp_cur = p_new; + return pp_cur - p_list->pp_head; + } + } + + /* Have to expand */ + size_t i_size = p_list->pp_tail - p_list->pp_head; + size_t i_newsize = i_size * 2; + p_list->pp_head = realloc( p_list->pp_head, + i_newsize * sizeof( overlay_t * ) ); + if( p_list->pp_head == NULL ) + return VLC_ENOMEM; + + p_list->pp_tail = p_list->pp_head + i_newsize; + memset( p_list->pp_head + i_size, 0, i_size * sizeof( overlay_t * ) ); + p_list->pp_head[i_size] = p_new; + return i_size; +} + +int ListRemove( list_t *p_list, size_t i_idx ) +{ + int ret; + + if( ( i_idx >= (size_t)( p_list->pp_tail - p_list->pp_head ) ) || + ( p_list->pp_head[i_idx] == NULL ) ) + { + return VLC_EGENERIC; + } + + ret = OverlayDestroy( p_list->pp_head[i_idx] ); + free( p_list->pp_head[i_idx] ); + p_list->pp_head[i_idx] = NULL; + + return ret; +} + +overlay_t *ListGet( list_t *p_list, size_t i_idx ) +{ + if( ( i_idx >= (size_t)( p_list->pp_tail - p_list->pp_head ) ) || + ( p_list->pp_head[i_idx] == NULL ) ) + { + return NULL; + } + return p_list->pp_head[i_idx]; +} + +overlay_t *ListWalk( list_t *p_list ) +{ + static overlay_t **pp_cur = NULL; + + if( pp_cur == NULL ) + pp_cur = p_list->pp_head; + else + pp_cur = pp_cur + 1; + + for( ; pp_cur < p_list->pp_tail; ++pp_cur ) + { + if( ( *pp_cur != NULL ) && + ( (*pp_cur)->b_active == VLC_TRUE )&& + ( (*pp_cur)->format.i_chroma != VLC_FOURCC( '\0','\0','\0','\0') ) ) + { + return *pp_cur; + } + } + pp_cur = NULL; + return NULL; +} diff --git a/modules/video_filter/dynamicoverlay/dynamicoverlay_queue.c b/modules/video_filter/dynamicoverlay/dynamicoverlay_queue.c new file mode 100644 index 0000000000..9fd757ad01 --- /dev/null +++ b/modules/video_filter/dynamicoverlay/dynamicoverlay_queue.c @@ -0,0 +1,115 @@ +/***************************************************************************** + * dynamicoverlay_commands.c : dynamic overlay plugin commands + ***************************************************************************** + * Copyright (C) 2008 the VideoLAN team + * $Id$ + * + * Author: Søren Bøg + * Jean-Paul Saman + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "dynamicoverlay.h" + +/***************************************************************************** + * queue_t: Command queue + *****************************************************************************/ + +int QueueInit( queue_t *p_queue ) +{ + memset( p_queue, 0, sizeof( queue_t ) ); + p_queue->p_head = NULL; + p_queue->p_tail = NULL; + + return VLC_SUCCESS; +} + +int QueueDestroy( queue_t *p_queue ) +{ + command_t *p_cur = p_queue->p_head, *p_temp; + while( p_cur != NULL ) + { + p_temp = p_cur; + p_cur = p_cur->p_next; + free( p_temp ); + } + p_queue->p_head = NULL; + p_queue->p_tail = NULL; + + return VLC_SUCCESS; +} + +int QueueEnqueue( queue_t *p_queue, command_t *p_cmd ) +{ + if( p_queue->p_tail != NULL ) + { + p_queue->p_tail->p_next = p_cmd; + } + if( p_queue->p_head == NULL ) + { + p_queue->p_head = p_cmd; + } + p_queue->p_tail = p_cmd; + p_cmd->p_next = NULL; + + return VLC_SUCCESS; +} + +command_t *QueueDequeue( queue_t *p_queue ) +{ + if( p_queue->p_head == NULL ) + { + return NULL; + } + else + { + command_t *p_ret = p_queue->p_head; + if( p_queue->p_head == p_queue->p_tail ) + { + p_queue->p_head = p_queue->p_tail = NULL; + } + else + { + p_queue->p_head = p_queue->p_head->p_next; + } + return p_ret; + } +} + +int QueueTransfer( queue_t *p_sink, queue_t *p_source ) +{ + if( p_source->p_head == NULL ) { + return VLC_SUCCESS; + } + + if( p_sink->p_head == NULL ) { + p_sink->p_head = p_source->p_head; + p_sink->p_tail = p_source->p_tail; + } else { + p_sink->p_tail->p_next = p_source->p_head; + p_sink->p_tail = p_source->p_tail; + } + p_source->p_head = p_source->p_tail = NULL; + + return VLC_SUCCESS; +} diff --git a/modules/video_filter/osdmenu.c b/modules/video_filter/osdmenu.c index c52644af1b..5ba5c17838 100644 --- a/modules/video_filter/osdmenu.c +++ b/modules/video_filter/osdmenu.c @@ -435,6 +435,7 @@ static subpicture_region_t *create_picture_region( filter_t *p_filter, subpictur p_region->i_x = 0; p_region->i_y = 0; p_region->i_align = p_filter->p_sys->i_position; + p_region->i_alpha = p_filter->p_sys->i_alpha; #if 0 msg_Dbg( p_filter, "SPU picture region position (%d,%d) (%d,%d) [%p]", p_region->i_x, p_region->i_y, diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c index 9dccc5324d..040345d6f5 100644 --- a/src/video_output/vout_subpictures.c +++ b/src/video_output/vout_subpictures.c @@ -291,6 +291,7 @@ subpicture_region_t *__spu_CreateRegion( vlc_object_t *p_this, if( !p_region ) return NULL; memset( p_region, 0, sizeof(subpicture_region_t) ); + p_region->i_alpha = 0xff; p_region->p_next = NULL; p_region->p_cache = NULL; p_region->fmt = *p_fmt; @@ -336,6 +337,7 @@ subpicture_region_t *__spu_MakeRegion( vlc_object_t *p_this, (void)p_this; if( !p_region ) return NULL; memset( p_region, 0, sizeof(subpicture_region_t) ); + p_region->i_alpha = 0xff; p_region->p_next = 0; p_region->p_cache = 0; p_region->fmt = *p_fmt; @@ -901,6 +903,7 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt, p_region->p_cache->i_x = p_region->i_x * pi_scale_width[ i_scale_idx ] / 1000; p_region->p_cache->i_y = p_region->i_y * pi_scale_height[ i_scale_idx ] / 1000; p_region->p_cache->i_align = p_region->i_align; + p_region->p_cache->i_alpha = p_region->i_alpha; p_pic = p_spu->p_scale->pf_video_filter( p_spu->p_scale, &p_region->p_cache->picture ); @@ -1060,7 +1063,7 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt, { p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst, p_pic_src, &p_region->picture, i_x_offset, i_y_offset, - i_fade_alpha * p_subpic->i_alpha / 255 ); + i_fade_alpha * p_subpic->i_alpha * p_region->i_alpha / 65025 ); } else { diff --git a/test/dynamicoverlay/Makefile b/test/dynamicoverlay/Makefile new file mode 100644 index 0000000000..18876ca537 --- /dev/null +++ b/test/dynamicoverlay/Makefile @@ -0,0 +1,4 @@ +all: overlay-test + +overlay-test: overlay-test.c + gcc -g2 --std=c99 -D_XOPEN_SOURCE=500 overlay-test.c -lm -o overlay-test diff --git a/test/dynamicoverlay/overlay-test.c b/test/dynamicoverlay/overlay-test.c new file mode 100644 index 0000000000..63774d5e47 --- /dev/null +++ b/test/dynamicoverlay/overlay-test.c @@ -0,0 +1,351 @@ +/***************************************************************************** + * overlay-test.c : test program for the dynamic overlay plugin + ***************************************************************************** + * Copyright (C) 2007 the VideoLAN team + * $Id$ + * + * Author: Søren Bøg + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/***************************************************************************** + * Images + *****************************************************************************/ + +#define WIDTH 128 +#define HEIGHT 128 + +#define TEXT "Hello world!" +#define TEXTSIZE sizeof( TEXT ) + +char *p_imageRGBA; +char *p_text; + +void DataCreate( void ) { + char *p_data = p_imageRGBA; + for( size_t i = 0; i < HEIGHT; ++i ) { + for( size_t j = 0; j < HEIGHT; ++j ) { + *(p_data++) = i * 4 & 0xFF; + *(p_data++) = 0xFF; + *(p_data++) = 0x00; + *(p_data++) = j * 4 & 0xFF; + } + } + + memcpy( p_text, TEXT, TEXTSIZE ); +} + +/***************************************************************************** + * I/O Helpers + *****************************************************************************/ + +int IsFailure( char *psz_text ) { + return strncmp( psz_text, "SUCCESS:", 8 ); +} + +void CheckResult( FILE *p_res ) { + char psz_resp[9]; + + fscanf( p_res, "%8s", &psz_resp ); + if( IsFailure( psz_resp ) ) { + printf( " failed\n" ); + exit( -1 ); + } +} + +void CheckedCommand( FILE *p_cmd, FILE *p_res, char *p_format, ... ) { + va_list ap; + va_start( ap, p_format ); + + vfprintf( p_cmd, p_format, ap ); + fflush( p_cmd ); + if( p_res != NULL ) { + CheckResult( p_res ); + } + va_end( ap ); +} + +int GenImage( FILE *p_cmd, FILE *p_res ) { + int i_overlay; + + printf( "Getting an overlay..." ); + CheckedCommand( p_cmd, p_res, "GenImage\n" ); + fscanf( p_res, "%d", &i_overlay ); + printf( " done. Overlay is %d\n", i_overlay ); + + return i_overlay; +} + +void DeleteImage( FILE *p_cmd, FILE *p_res, int i_overlay ) { + printf( "Removing image..." ); + CheckedCommand( p_cmd, p_res, "DeleteImage %d\n", i_overlay ); + printf( " done\n" ); +} + +void StartAtomic( FILE *p_cmd, FILE *p_res ) { + CheckedCommand( p_cmd, p_res, "StartAtomic\n" ); +} + +void EndAtomic( FILE *p_cmd, FILE *p_res ) { + CheckedCommand( p_cmd, p_res, "EndAtomic\n" ); +} + +void DataSharedMem( FILE *p_cmd, FILE *p_res, int i_overlay, int i_width, + int i_height, char *psz_format, int i_shmid ) { + + printf( "Sending data via shared memory..." ); + CheckedCommand( p_cmd, p_res, "DataSharedMem %d %d %d %s %d\n", i_overlay, + i_width, i_height, psz_format, i_shmid ); + printf( " done\n" ); +} + +void SetAlpha( FILE *p_cmd, FILE *p_res, int i_overlay, int i_alpha ) { + CheckedCommand( p_cmd, p_res, "SetAlpha %d %d\n", i_overlay, i_alpha ); +} + +void SetPosition( FILE *p_cmd, FILE *p_res, int i_overlay, int i_x, int i_y ) { + CheckedCommand( p_cmd, p_res, "SetPosition %d %d %d\n", i_overlay, i_x, + i_y ); +} + +void SetVisibility( FILE *p_cmd, FILE *p_res, int i_overlay, int i_visible ) { + CheckedCommand( p_cmd, p_res, "SetVisibility %d %d\n", i_overlay, + i_visible ); +} + +void SetTextAlpha( FILE *p_cmd, FILE *p_res, int i_overlay, int i_alpha ) { + CheckedCommand( p_cmd, p_res, "SetTextAlpha %d %d\n", i_overlay, i_alpha ); +} + +void SetTextColor( FILE *p_cmd, FILE *p_res, int i_overlay, int i_red, + int i_green, int i_blue ) { + CheckedCommand( p_cmd, p_res, "SetTextColor %d %d %d %d\n", i_overlay, + i_red, i_green, i_blue ); +} + +void SetTextSize( FILE *p_cmd, FILE *p_res, int i_overlay, int i_size ) { + CheckedCommand( p_cmd, p_res, "SetTextSize %d %d\n", i_overlay, i_size ); +} + +int GetTextSize( FILE *p_cmd, FILE *p_res, int i_overlay ) { + int i_size; + + CheckedCommand( p_cmd, p_res, "GetTextSize %d\n", i_overlay ); + fscanf( p_res, "%d", &i_size ); + + return i_size; +} + +/***************************************************************************** + * Test Routines + *****************************************************************************/ + +void BasicTest( FILE *p_cmd, FILE *p_res, int i_overlay ) { + printf( "Activating overlay..." ); + SetVisibility( p_cmd, p_res, i_overlay, 1 ); + printf( " done\n" ); + + printf( "Sweeping alpha..." ); + for( int i_alpha = 0xFF; i_alpha >= -0xFF ; i_alpha -= 8 ) { + SetAlpha( p_cmd, p_res, i_overlay, abs( i_alpha ) ); + usleep( 20000 ); + } + SetAlpha( p_cmd, p_res, i_overlay, 255 ); + printf( " done\n" ); + + printf( "Circle motion..." ); + for( float f_theta = 0; f_theta <= 2 * M_PI ; f_theta += M_PI / 64.0 ) { + SetPosition( p_cmd, p_res, i_overlay, + (int)( - cos( f_theta ) * 100.0 + 100.0 ), + (int)( - sin( f_theta ) * 100.0 + 100.0 ) ); + usleep( 20000 ); + } + SetPosition( p_cmd, p_res, i_overlay, 0, 100 ); + printf( " done\n" ); + + printf( "Atomic motion..." ); + StartAtomic( p_cmd, p_res ); + SetPosition( p_cmd, NULL, i_overlay, 200, 50 ); + sleep( 1 ); + SetPosition( p_cmd, NULL, i_overlay, 0, 0 ); + EndAtomic( p_cmd, p_res ); + CheckResult( p_res ); + CheckResult( p_res ); + printf( " done\n" ); + + sleep( 5 ); +} + +void TextTest( FILE *p_cmd, FILE *p_res, int i_overlay ) { + printf( "Sweeping (text) alpha..." ); + for( int i_alpha = 0xFF; i_alpha >= -0xFF ; i_alpha -= 8 ) { + SetTextAlpha( p_cmd, p_res, i_overlay, abs( i_alpha ) ); + usleep( 20000 ); + } + SetTextAlpha( p_cmd, p_res, i_overlay, 255 ); + printf( " done\n" ); + + printf( "Sweeping colors..." ); + for( int i_red = 0xFF; i_red >= 0x00 ; i_red -= 8 ) { + SetTextColor( p_cmd, p_res, i_overlay, i_red, 0xFF, 0xFF ); + usleep( 20000 ); + } + for( int i_green = 0xFF; i_green >= 0x00 ; i_green -= 8 ) { + SetTextColor( p_cmd, p_res, i_overlay, 0x00, i_green, 0xFF ); + usleep( 20000 ); + } + for( int i_blue = 0xFF; i_blue >= 0x00 ; i_blue -= 8 ) { + SetTextColor( p_cmd, p_res, i_overlay, 0x00, 0x00, i_blue ); + usleep( 20000 ); + } + SetTextColor( p_cmd, p_res, i_overlay, 0x00, 0x00, 0x00 ); + printf( " done\n" ); + + printf( "Getting size..." ); + int i_basesize = GetTextSize( p_cmd, p_res, i_overlay ); + printf( " done. Size is %d\n", i_basesize ); + + printf( "Sweeping size..." ); + for( float f_theta = 0; f_theta <= M_PI ; f_theta += M_PI / 128.0 ) { + SetTextSize( p_cmd, p_res, i_overlay, + i_basesize * ( 1 + 3 * sin( f_theta ) ) ); + usleep( 20000 ); + } + SetTextSize( p_cmd, p_res, i_overlay, i_basesize ); + printf( " done\n" ); + + sleep( 5 ); +} + +/***************************************************************************** + * main + *****************************************************************************/ + +int main( int i_argc, char *ppsz_argv[] ) { + if( i_argc != 3 ) { + printf( "Incorrect number of parameters.\n" + "Usage is: %s command-fifo response-fifo\n", ppsz_argv[0] ); + exit( -2 ); + } + + printf( "Creating shared memory for RGBA..." ); + int i_shmRGBA = shmget( IPC_PRIVATE, WIDTH * HEIGHT * 4, S_IRWXU ); + if( i_shmRGBA == -1 ) { + printf( " failed\n" ); + exit( -1 ); + } + printf( " done, ID is %d. Text...", i_shmRGBA ); + int i_shmText = shmget( IPC_PRIVATE, TEXTSIZE, S_IRWXU ); + if( i_shmText == -1 ) { + printf( " failed\n" ); + exit( -1 ); + } + printf( " done, ID is %d\n", i_shmText ); + + printf( "Attaching shared memory for RGBA..." ); + p_imageRGBA = shmat( i_shmRGBA, NULL, 0 ); + if( p_imageRGBA == (void*)-1 ) { + printf( " failed\n" ); + exit( -1 ); + } + printf( " done. Text..." ); + p_text = shmat( i_shmText, NULL, 0 ); + if( p_text == (void*)-1 ) { + printf( " failed\n" ); + exit( -1 ); + } + printf( " done\n" ); + + printf( "Queueing shared memory for destruction, RGBA..." ); + if( shmctl( i_shmRGBA, IPC_RMID, 0 ) == -1 ) { + printf( " failed\n" ); + exit( -1 ); + } + printf( " done. Text..." ); + if( shmctl( i_shmText, IPC_RMID, 0 ) == -1 ) { + printf( " failed\n" ); + exit( -1 ); + } + printf( " done\n" ); + + printf( "Generating data..." ); + DataCreate(); + printf( " done\n" ); + + printf( "Making FIFOs..." ); + if( mkfifo( ppsz_argv[1], S_IRWXU ) ) { + if( errno != EEXIST ) { + printf( " failed\n" ); + exit( -1 ); + } + printf( " input already exists..." ); + } + if( mkfifo( ppsz_argv[2], S_IRWXU ) ) { + if( errno != EEXIST ) { + printf( " failed\n" ); + exit( -1 ); + } + printf( " output already exists..." ); + } + printf( " done\n" ); + + printf( "Please make sure vlc is running.\n" + "You should append parameters similar to the following:\n" + "--sub-filter overlay{input=%s,output=%s}\n", + ppsz_argv[1], ppsz_argv[2] ); + + printf( "Opening FIFOs..." ); + FILE *p_cmd = fopen( ppsz_argv[1], "w" ); + if( p_cmd == NULL ) { + printf( " failed\n" ); + exit( -1 ); + } + FILE *p_res = fopen( ppsz_argv[2], "r" ); + if( p_res == NULL ) { + printf( " failed\n" ); + exit( -1 ); + } + printf( " done\n" ); + + int i_overlay_image = GenImage( p_cmd, p_res ); + int i_overlay_text = GenImage( p_cmd, p_res ); + DataSharedMem( p_cmd, p_res, i_overlay_image, WIDTH, HEIGHT, "RGBA", + i_shmRGBA ); + DataSharedMem( p_cmd, p_res, i_overlay_text, TEXTSIZE, 1, "TEXT", + i_shmText ); + + BasicTest( p_cmd, p_res, i_overlay_image ); + BasicTest( p_cmd, p_res, i_overlay_text ); + TextTest( p_cmd, p_res, i_overlay_text ); + + DeleteImage( p_cmd, p_res, i_overlay_image ); + DeleteImage( p_cmd, p_res, i_overlay_text ); +}