/*****************************************************************************
* video_output.c : video output thread
- * (c)2000 VideoLAN
- *****************************************************************************
* This module describes the programming interface for video output threads.
* It includes functions allowing to open a new thread, send pictures to a
- * thread, and destroy a previously oppenned video output thread.
+ * thread, and destroy a previously oppened video output thread.
+ *****************************************************************************
+ * Copyright (C) 2000 VideoLAN
+ *
+ * Authors:
+ *
+ * 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
*****************************************************************************/
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "defs.h"
-#include <dlfcn.h> /* plugins */
+#include <errno.h> /* ENOMEM */
+#include <stdlib.h> /* free() */
+#include <stdio.h> /* sprintf() */
+#include <string.h> /* strerror() */
-#include "common.h"
#include "config.h"
+#include "common.h"
+#include "threads.h"
#include "mtime.h"
-#include "vlc_thread.h"
+#include "plugins.h"
#include "video.h"
#include "video_output.h"
#include "video_text.h"
+#include "video_spu.h"
#include "video_yuv.h"
+
#include "intf_msg.h"
#include "main.h"
* If not, it will be updated using one of the THREAD_* constants.
*****************************************************************************/
vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_window,
- int i_width, int i_height, int *pi_status, int i_method )
+ int i_width, int i_height, int *pi_status,
+ int i_method, void *p_data )
{
vout_thread_t * p_vout; /* thread descriptor */
int i_status; /* thread status */
int i_index; /* index for array initialization */
char * psz_method;
- char * psz_plugin;
/* Allocate descriptor */
intf_DbgMsg("\n");
return( NULL );
}
- /* Initialize method-dependent functions */
+ /* Request an interface plugin */
psz_method = main_GetPszVariable( VOUT_METHOD_VAR, VOUT_DEFAULT_METHOD );
- psz_plugin = malloc( sizeof("./video_output/vout_.so") + strlen(psz_method) );
- sprintf( psz_plugin, "./video_output/vout_%s.so", psz_method );
-
- p_vout->p_vout_plugin = dlopen( psz_plugin, RTLD_NOW | RTLD_GLOBAL );
-
- if( p_vout->p_vout_plugin == NULL )
+ if( RequestPlugin( &p_vout->vout_plugin, psz_method ) < 0 )
{
- intf_ErrMsg( "error: could not open video plugin %s\n", psz_plugin );
- free( psz_plugin );
+ intf_ErrMsg( "error: could not open video plugin %s.so\n", psz_method );
free( p_vout );
return( NULL );
}
- free( psz_plugin );
/* Get plugins */
- p_vout->p_sys_create = dlsym(p_vout->p_vout_plugin, "vout_SysCreate");
- p_vout->p_sys_init = dlsym(p_vout->p_vout_plugin, "vout_SysInit");
- p_vout->p_sys_end = dlsym(p_vout->p_vout_plugin, "vout_SysEnd");
- p_vout->p_sys_destroy = dlsym(p_vout->p_vout_plugin, "vout_SysDestroy");
- p_vout->p_sys_manage = dlsym(p_vout->p_vout_plugin, "vout_SysManage");
- p_vout->p_sys_display = dlsym(p_vout->p_vout_plugin, "vout_SysDisplay");
+ p_vout->p_sys_create =
+ GetPluginFunction( p_vout->vout_plugin, "vout_SysCreate" );
+ p_vout->p_sys_init =
+ GetPluginFunction( p_vout->vout_plugin, "vout_SysInit" );
+ p_vout->p_sys_end =
+ GetPluginFunction( p_vout->vout_plugin, "vout_SysEnd" );
+ p_vout->p_sys_destroy =
+ GetPluginFunction( p_vout->vout_plugin, "vout_SysDestroy" );
+ p_vout->p_sys_manage =
+ GetPluginFunction( p_vout->vout_plugin, "vout_SysManage" );
+ p_vout->p_sys_display =
+ GetPluginFunction( p_vout->vout_plugin, "vout_SysDisplay" );
/* Initialize thread properties - thread id and locks will be initialized
* later */
p_vout->i_bytes_per_pixel = 2;
p_vout->f_gamma = VOUT_GAMMA;
- p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR, VOUT_GRAYSCALE_DEFAULT );
+ p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
+ VOUT_GRAYSCALE_DEFAULT );
p_vout->b_info = 0;
p_vout->b_interface = 0;
p_vout->b_scale = 0;
p_vout->p_set_palette = SetPalette;
- intf_DbgMsg("wished configuration: %dx%d, %d/%d bpp (%d Bpl)\n",
- p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
- p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line );
+ intf_DbgMsg( "wished configuration: %dx%d, %d/%d bpp (%d Bpl)\n",
+ p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
+ p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line );
/* Initialize idle screen */
p_vout->last_display_date = mdate();
{
p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
p_vout->p_picture[i_index].i_status = FREE_PICTURE;
+ }
+ for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
+ {
p_vout->p_subpicture[i_index].i_type = EMPTY_SUBPICTURE;
p_vout->p_subpicture[i_index].i_status= FREE_SUBPICTURE;
}
/* Create and initialize system-dependant method - this function issues its
* own error messages */
- if( p_vout->p_sys_create( p_vout, psz_display, i_root_window ) )
+ if( p_vout->p_sys_create( p_vout, psz_display, i_root_window, p_data ) )
{
- dlclose( p_vout->p_vout_plugin );
+ TrashPlugin( p_vout->vout_plugin );
free( p_vout );
return( NULL );
}
/* Load fonts - fonts must be initialized after the system method since
* they may be dependant on screen depth and other thread properties */
- p_vout->p_default_font = vout_LoadFont( VOUT_DEFAULT_FONT );
+ p_vout->p_default_font = vout_LoadFont( DATA_PATH "/" VOUT_DEFAULT_FONT );
+ if( p_vout->p_default_font == NULL )
+ {
+ p_vout->p_default_font = vout_LoadFont( "share/" VOUT_DEFAULT_FONT );
+ }
if( p_vout->p_default_font == NULL )
{
p_vout->p_sys_destroy( p_vout );
- dlclose( p_vout->p_vout_plugin );
+ TrashPlugin( p_vout->vout_plugin );
free( p_vout );
return( NULL );
}
- p_vout->p_large_font = vout_LoadFont( VOUT_LARGE_FONT );
+ p_vout->p_large_font = vout_LoadFont( DATA_PATH "/" VOUT_LARGE_FONT );
+ if( p_vout->p_large_font == NULL )
+ {
+ p_vout->p_large_font = vout_LoadFont( "share/" VOUT_LARGE_FONT );
+ }
if( p_vout->p_large_font == NULL )
{
vout_UnloadFont( p_vout->p_default_font );
p_vout->p_sys_destroy( p_vout );
- dlclose( p_vout->p_vout_plugin );
+ TrashPlugin( p_vout->vout_plugin );
free( p_vout );
return( NULL );
}
vout_UnloadFont( p_vout->p_default_font );
vout_UnloadFont( p_vout->p_large_font );
p_vout->p_sys_destroy( p_vout );
- dlclose( p_vout->p_vout_plugin );
+ TrashPlugin( p_vout->vout_plugin );
free( p_vout );
return( NULL );
}
/*
* Look for an empty place
*/
- for( i_subpic = 0; i_subpic < VOUT_MAX_PICTURES; i_subpic++ )
+ for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
{
if( p_vout->p_subpicture[i_subpic].i_status == DESTROYED_SUBPICTURE )
{
if( (p_vout->p_subpicture[i_subpic].i_type == i_type) &&
(p_vout->p_subpicture[i_subpic].i_size >= i_size) )
{
- /* Memory size do match or is smaller : memory will not be reallocated,
- * and function can end immediately - this is the best possible case,
- * since no memory allocation needs to be done */
+ /* Memory size do match or is smaller : memory will not be
+ * reallocated, and function can end immediately - this is
+ * the best possible case, since no memory allocation needs
+ * to be done */
p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
#ifdef DEBUG_VIDEO
intf_DbgMsg("subpicture %p (in destroyed subpicture slot)\n",
/* If no free subpicture is available, use a destroyed subpicture */
if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
{
- /* No free subpicture or matching destroyed subpicture has been found, but
- * a destroyed subpicture is still avalaible */
+ /* No free subpicture or matching destroyed subpicture has been
+ * found, but a destroyed subpicture is still avalaible */
free( p_destroyed_subpic->p_data );
p_free_subpic = p_destroyed_subpic;
}
case TEXT_SUBPICTURE: /* text subpicture */
p_free_subpic->p_data = malloc( i_size + 1 );
break;
+ case DVD_SUBPICTURE: /* DVD subpicture unit */
+ p_free_subpic->p_data = malloc( i_size );
+ break;
#ifdef DEBUG
default:
intf_DbgMsg("error: unknown subpicture type %d\n", i_type );
}
if( p_free_subpic->p_data != NULL )
- { /* Copy subpicture informations, set some default values */
+ { /* Copy subpicture informations, set some default values */
p_free_subpic->i_type = i_type;
p_free_subpic->i_status = RESERVED_SUBPICTURE;
p_free_subpic->i_size = i_size;
#if 1
if( display_date < current_date && i_trash_count > 4 )
{
- /* Picture is late: it will be destroyed and the thread will sleep and
- * go to next picture */
+ /* Picture is late: it will be destroyed and the thread
+ * will sleep and go to next picture */
vlc_mutex_lock( &p_vout->picture_lock );
if( p_pic->i_refcount )
#endif
if( display_date > current_date + VOUT_DISPLAY_DELAY )
{
- /* A picture is ready to be rendered, but its rendering date is
- * far from the current one so the thread will perform an empty loop
- * as if no picture were found. The picture state is unchanged */
+ /* A picture is ready to be rendered, but its rendering date
+ * is far from the current one so the thread will perform an
+ * empty loop as if no picture were found. The picture state
+ * is unchanged */
p_pic = NULL;
display_date = 0;
}
}
}
/*
- * Find the subpicture to display - this operation does not need lock, since
- * only READY_SUBPICTURES are handled. If no picture has been selected,
- * display_date will depend on the subpicture
+ * Find the subpictures to display - this operation does not need
+ * lock, since only READY_SUBPICTURE are handled. If no picture
+ * has been selected, display_date will depend on the subpicture.
+ * We get an easily parsable chained list of subpictures which
+ * ends with NULL since p_subpic was initialized to NULL.
*/
- /* XXX?? */
+ for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
+ {
+ if( p_vout->p_subpicture[i_index].i_status == READY_SUBPICTURE )
+ {
+ p_vout->p_subpicture[i_index].p_next = p_subpic;
+ p_subpic = &p_vout->p_subpicture[i_index];
+ }
+ }
/*
* Perform rendering, sleep and display rendered picture
RenderPictureInfo( p_vout, p_pic );
RenderInfo( p_vout );
}
+ if( p_subpic )
+ {
+ RenderSubPicture( p_vout, p_subpic );
+ }
}
/* Remove picture from heap */
{
RenderInterface( p_vout );
}
- if( p_subpic )
- {
- if( b_display )
- {
- RenderSubPicture( p_vout, p_subpic );
- }
-
- /* Remove subpicture from heap */
- vlc_mutex_lock( &p_vout->subpicture_lock );
- p_subpic->i_status = DESTROYED_SUBPICTURE;
- vlc_mutex_unlock( &p_vout->subpicture_lock );
- }
}
- else if( p_subpic ) /* subpicture alone */
- {
- b_display = p_vout->b_active;
- p_vout->last_display_date = display_date;
-
- if( b_display )
- {
- /* Clear buffer */
- SetBufferPicture( p_vout, NULL );
-
- /* Render informations, interface and subpicture */
- if( p_vout->b_info )
- {
- RenderInfo( p_vout );
- }
- if( p_vout->b_interface )
- {
- RenderInterface( p_vout );
- }
- RenderSubPicture( p_vout, p_subpic );
- }
-
- /* Remove subpicture from heap */
- vlc_mutex_lock( &p_vout->subpicture_lock );
- p_subpic->i_status = DESTROYED_SUBPICTURE;
- vlc_mutex_unlock( &p_vout->subpicture_lock );
- }
else if( p_vout->b_active ) /* idle or interface screen alone */
{
if( p_vout->b_interface && 0 /* && XXX?? intf_change */ )
if( b_display && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
{
p_vout->p_sys_display( p_vout );
+#ifndef SYS_BEOS
p_vout->i_buffer_index = ++p_vout->i_buffer_index & 1;
+#endif
}
/*
/*****************************************************************************
* EndThread: thread destruction
*****************************************************************************
- * This function is called when the thread ends after a sucessfull
+ * This function is called when the thread ends after a sucessful
* initialization. It frees all ressources allocated by InitThread.
*****************************************************************************/
static void EndThread( vout_thread_t *p_vout )
{
free( p_vout->p_picture[i_index].p_data );
}
+ }
+ for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
+ {
if( p_vout->p_subpicture[i_index].i_status != FREE_SUBPICTURE )
{
free( p_vout->p_subpicture[i_index].p_data );
p_vout->p_sys_destroy( p_vout );
/* Close plugin */
- dlclose( p_vout->p_vout_plugin );
+ TrashPlugin( p_vout->vout_plugin );
/* Free structure */
free( p_vout );
}
/*
- * Set new picture size - if is is smaller than the previous one, clear
+ * Set new picture size - if it is smaller than the previous one, clear
* around it. Since picture are centered, only their size is tested.
*/
if( (p_buffer->i_pic_width > i_pic_width) || (p_buffer->i_pic_height > i_pic_height) )
/* Get and set rendering informations */
p_buffer = &p_vout->p_buffer[ p_vout->i_buffer_index ];
p_pic_data = p_buffer->p_data +
- p_buffer->i_pic_x * p_vout->i_bytes_per_pixel +
- p_buffer->i_pic_y * p_vout->i_bytes_per_line;
+ p_buffer->i_pic_x * p_vout->i_bytes_per_pixel +
+ p_buffer->i_pic_y * p_vout->i_bytes_per_line;
#ifdef DEBUG_VIDEO
render_time = mdate();
#endif
p_vout_font_t p_font; /* text font */
int i_width, i_height; /* subpicture dimensions */
- switch( p_subpic->i_type )
+ while( p_subpic != NULL )
{
- case TEXT_SUBPICTURE: /* single line text */
- /* Select default font if not specified */
- p_font = p_subpic->type.text.p_font;
- if( p_font == NULL )
+ switch( p_subpic->i_type )
{
- p_font = p_vout->p_default_font;
- }
+ case DVD_SUBPICTURE: /* DVD subpicture unit */
+ /* test if the picture really has to be displayed */
+ if( mdate() < p_subpic->begin_date )
+ {
+ /* not yet, see you later */
+ break;
+ }
+ if( mdate() > p_subpic->end_date )
+ {
+ /* too late, destroying the subpic */
+ vout_DestroySubPicture( p_vout, p_subpic );
+ break;
+ }
+ vout_RenderSPU( &p_vout->p_buffer[ p_vout->i_buffer_index ],
+ p_subpic, p_vout->i_bytes_per_pixel,
+ p_vout->i_bytes_per_line );
+ break;
+ case TEXT_SUBPICTURE: /* single line text */
+ /* Select default font if not specified */
+ p_font = p_subpic->type.text.p_font;
+ if( p_font == NULL )
+ {
+ p_font = p_vout->p_default_font;
+ }
- /* Computes text size (width and height fields are ignored) and print it */
- vout_TextSize( p_font, p_subpic->type.text.i_style, p_subpic->p_data, &i_width, &i_height );
- if( !Align( p_vout, &p_subpic->i_x, &p_subpic->i_y, i_width, i_height,
- p_subpic->i_horizontal_align, p_subpic->i_vertical_align ) )
- {
- vout_Print( p_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
- p_subpic->i_x * p_vout->i_bytes_per_pixel +
- p_subpic->i_y * p_vout->i_bytes_per_line,
- p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
- p_subpic->type.text.i_char_color, p_subpic->type.text.i_border_color,
- p_subpic->type.text.i_bg_color, p_subpic->type.text.i_style,
- p_subpic->p_data );
- SetBufferArea( p_vout, p_subpic->i_x, p_subpic->i_y, i_width, i_height );
- }
- break;
+ /* Compute text size (width and height fields are ignored)
+ * and print it */
+ vout_TextSize( p_font, p_subpic->type.text.i_style,
+ p_subpic->p_data, &i_width, &i_height );
+ if( !Align( p_vout, &p_subpic->i_x, &p_subpic->i_y,
+ i_width, i_height, p_subpic->i_horizontal_align,
+ p_subpic->i_vertical_align ) )
+ {
+ vout_Print( p_font,
+ p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
+ p_subpic->i_x * p_vout->i_bytes_per_pixel +
+ p_subpic->i_y * p_vout->i_bytes_per_line,
+ p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
+ p_subpic->type.text.i_char_color,
+ p_subpic->type.text.i_border_color,
+ p_subpic->type.text.i_bg_color,
+ p_subpic->type.text.i_style, p_subpic->p_data );
+ SetBufferArea( p_vout, p_subpic->i_x, p_subpic->i_y,
+ i_width, i_height );
+ }
+ break;
#ifdef DEBUG
- default:
- intf_DbgMsg("error: unknown subpicture %p type %d\n", p_subpic, p_subpic->i_type );
+ default:
+ intf_DbgMsg( "error: unknown subpicture %p type %d\n",
+ p_subpic, p_subpic->i_type );
#endif
+ }
+
+ p_subpic = p_subpic->p_next;
}
}