📄 video_output.c
字号:
/***************************************************************************** * video_output.c : video output thread * * 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 oppened video output thread. ***************************************************************************** * Copyright (C) 2000-2007 the VideoLAN team * $Id: f54ec25fa1e35cadff4904450529563cdd6eed99 $ * * Authors: Vincent Seguin <seguin@via.ecp.fr> * Gildas Bazin <gbazin@videolan.org> * * 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 <vlc_common.h>#include <stdlib.h> /* free() */#include <string.h>#ifdef HAVE_SYS_TIMES_H# include <sys/times.h>#endif#include <vlc_vout.h>#include <vlc_filter.h>#include <vlc_osd.h>#if defined( __APPLE__ )/* Include darwin_specific.h here if needed */#endif/** FIXME This is quite ugly but needed while we don't have counters * helpers */#include "input/input_internal.h"#include "modules/modules.h"#include <assert.h>#include "vout_pictures.h"/***************************************************************************** * Local prototypes *****************************************************************************/static int InitThread ( vout_thread_t * );static void* RunThread ( vlc_object_t * );static void ErrorThread ( vout_thread_t * );static void CleanThread ( vout_thread_t * );static void EndThread ( vout_thread_t * );static void AspectRatio ( int, int *, int * );static void VideoFormatImportRgb( video_format_t *, const picture_heap_t * );static void PictureHeapFixRgb( picture_heap_t * );static void vout_Destructor ( vlc_object_t * p_this );/* Object variables callbacks */static int DeinterlaceCallback( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );static int FilterCallback( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );static int VideoFilter2Callback( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );/* From vout_intf.c */int vout_Snapshot( vout_thread_t *, picture_t * );/* Display media title in OSD */static void DisplayTitleOnOSD( vout_thread_t *p_vout );/* */static void DropPicture( vout_thread_t *p_vout, picture_t *p_picture );/***************************************************************************** * Video Filter2 functions *****************************************************************************/static picture_t *video_new_buffer_filter( filter_t *p_filter ){ vout_thread_t *p_vout = (vout_thread_t*)p_filter->p_owner; picture_t *p_picture = vout_CreatePicture( p_vout, 0, 0, 0 ); p_picture->i_status = READY_PICTURE; return p_picture;}static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic ){ vout_thread_t *p_vout = (vout_thread_t*)p_filter->p_owner; DropPicture( p_vout, p_pic );}static int video_filter_buffer_allocation_init( filter_t *p_filter, void *p_data ){ p_filter->pf_vout_buffer_new = video_new_buffer_filter; p_filter->pf_vout_buffer_del = video_del_buffer_filter; p_filter->p_owner = p_data; /* p_vout */ return VLC_SUCCESS;}/***************************************************************************** * vout_Request: find a video output thread, create one, or destroy one. ***************************************************************************** * This function looks for a video output thread matching the current * properties. If not found, it spawns a new one. *****************************************************************************/vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, video_format_t *p_fmt ){ const bool b_vout_provided = p_vout != NULL; if( !p_fmt ) { /* Video output is no longer used. * TODO: support for reusing video outputs with proper _thread-safe_ * reference handling. */ if( p_vout ) vout_CloseAndRelease( p_vout ); return NULL; } /* If a video output was provided, lock it, otherwise look for one. */ if( p_vout ) { vlc_object_yield( p_vout ); } /* TODO: find a suitable unused video output */ /* If we now have a video output, check it has the right properties */ if( p_vout ) { char *psz_filter_chain; vlc_value_t val; vlc_mutex_lock( &p_vout->change_lock ); /* We don't directly check for the "vout-filter" variable for obvious * performance reasons. */ if( p_vout->b_filter_change ) { var_Get( p_vout, "vout-filter", &val ); psz_filter_chain = val.psz_string; if( psz_filter_chain && !*psz_filter_chain ) { free( psz_filter_chain ); psz_filter_chain = NULL; } if( p_vout->psz_filter_chain && !*p_vout->psz_filter_chain ) { free( p_vout->psz_filter_chain ); p_vout->psz_filter_chain = NULL; } if( !psz_filter_chain && !p_vout->psz_filter_chain ) { p_vout->b_filter_change = false; } free( psz_filter_chain ); } if( p_vout->fmt_render.i_chroma != p_fmt->i_chroma || p_vout->fmt_render.i_width != p_fmt->i_width || p_vout->fmt_render.i_height != p_fmt->i_height || p_vout->b_filter_change ) { vlc_mutex_unlock( &p_vout->change_lock ); /* We are not interested in this format, close this vout */ vout_CloseAndRelease( p_vout ); vlc_object_release( p_vout ); p_vout = NULL; } else { /* This video output is cool! Hijack it. */ if( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) { /* Correct aspect ratio on change * FIXME factorize this code with other aspect ration related code */ unsigned int i_sar_num; unsigned int i_sar_den; unsigned int i_aspect; i_aspect = p_fmt->i_aspect; vlc_ureduce( &i_sar_num, &i_sar_den, p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 );#if 0 /* What's that, it does not seems to be used correcly everywhere * beside the previous p_vout->fmt_render.i_aspect != p_fmt->i_aspect * should be fixed to use it too then */ if( p_vout->i_par_num > 0 && p_vout->i_par_den > 0 ) { i_sar_num *= p_vout->i_par_den; i_sar_den *= p_vout->i_par_num; i_aspect = i_aspect * p_vout->i_par_den / p_vout->i_par_num; }#endif if( i_sar_num > 0 && i_sar_den > 0 && i_aspect > 0 ) { p_vout->fmt_in.i_sar_num = i_sar_num; p_vout->fmt_in.i_sar_den = i_sar_den; p_vout->fmt_in.i_aspect = i_aspect; p_vout->fmt_render.i_sar_num = i_sar_num; p_vout->fmt_render.i_sar_den = i_sar_den; p_vout->fmt_render.i_aspect = i_aspect; p_vout->render.i_aspect = i_aspect; p_vout->i_changes |= VOUT_ASPECT_CHANGE; } } vlc_mutex_unlock( &p_vout->change_lock ); vlc_object_release( p_vout ); } if( p_vout ) { msg_Dbg( p_this, "reusing provided vout" ); spu_Attach( p_vout->p_spu, p_this, true ); vlc_object_detach( p_vout ); vlc_object_attach( p_vout, p_this ); /* Display title if we are not using the vout given to vout_Request. * XXX for now b_vout_provided is always true at this stage */ if( p_vout->b_title_show && !b_vout_provided ) DisplayTitleOnOSD( p_vout ); } } if( !p_vout ) { msg_Dbg( p_this, "no usable vout present, spawning one" ); p_vout = vout_Create( p_this, p_fmt ); } return p_vout;}/***************************************************************************** * vout_Create: creates a new video output thread ***************************************************************************** * This function creates a new video output thread, and returns a pointer * to its description. On error, it returns NULL. *****************************************************************************/vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ){ vout_thread_t * p_vout; /* thread descriptor */ input_thread_t * p_input_thread; int i_index; /* loop variable */ vlc_value_t val, text; unsigned int i_width = p_fmt->i_width; unsigned int i_height = p_fmt->i_height; vlc_fourcc_t i_chroma = p_fmt->i_chroma; unsigned int i_aspect = p_fmt->i_aspect; config_chain_t *p_cfg; char *psz_parser; char *psz_name; if( i_width <= 0 || i_height <= 0 || i_aspect <= 0 ) return NULL; vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den, p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 ); if( p_fmt->i_sar_num <= 0 || p_fmt->i_sar_den <= 0 ) return NULL; /* Allocate descriptor */ static const char typename[] = "video output"; p_vout = vlc_custom_create( p_parent, sizeof( *p_vout ), VLC_OBJECT_VOUT, typename ); if( p_vout == NULL ) return NULL; /* Initialize pictures - translation tables and functions * will be initialized later in InitThread */ for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++) { p_vout->p_picture[i_index].pf_lock = NULL; p_vout->p_picture[i_index].pf_unlock = NULL; p_vout->p_picture[i_index].i_status = FREE_PICTURE; p_vout->p_picture[i_index].i_type = EMPTY_PICTURE; p_vout->p_picture[i_index].b_slow = 0; } /* No images in the heap */ p_vout->i_heap_size = 0; /* Initialize the rendering heap */ I_RENDERPICTURES = 0; p_vout->fmt_render = *p_fmt; /* FIXME palette */ p_vout->fmt_in = *p_fmt; /* FIXME palette */ p_vout->render.i_width = i_width; p_vout->render.i_height = i_height; p_vout->render.i_chroma = i_chroma; p_vout->render.i_aspect = i_aspect; p_vout->render.i_rmask = p_fmt->i_rmask; p_vout->render.i_gmask = p_fmt->i_gmask; p_vout->render.i_bmask = p_fmt->i_bmask; p_vout->render.i_last_used_pic = -1; p_vout->render.b_allow_modify_pics = 1; /* Zero the output heap */ I_OUTPUTPICTURES = 0; p_vout->output.i_width = 0; p_vout->output.i_height = 0; p_vout->output.i_chroma = 0; p_vout->output.i_aspect = 0; p_vout->output.i_rmask = 0; p_vout->output.i_gmask = 0; p_vout->output.i_bmask = 0; /* Initialize misc stuff */ p_vout->i_changes = 0; p_vout->f_gamma = 0; p_vout->b_grayscale = 0; p_vout->b_info = 0; p_vout->b_interface = 0; p_vout->b_scale = 1; p_vout->b_fullscreen = 0; p_vout->i_alignment = 0; p_vout->render_time = 10; p_vout->c_fps_samples = 0; p_vout->b_filter_change = 0; p_vout->pf_control = NULL; p_vout->p_window = NULL; p_vout->i_par_num = p_vout->i_par_den = 1; /* Initialize locks */ vlc_mutex_init( &p_vout->picture_lock ); vlc_mutex_init( &p_vout->change_lock ); vlc_mutex_init( &p_vout->vfilter_lock ); /* Mouse coordinates */ var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER ); var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER ); var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER ); var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL ); var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER ); /* Initialize subpicture unit */ p_vout->p_spu = spu_Create( p_vout ); spu_Attach( p_vout->p_spu, p_parent, true ); /* Attach the new object now so we can use var inheritance below */ vlc_object_attach( p_vout, p_parent ); spu_Init( p_vout->p_spu ); /* Take care of some "interface/control" related initialisations */ vout_IntfInit( p_vout ); /* If the parent is not a VOUT object, that means we are at the start of * the video output pipe */ if( p_parent->i_object_type != VLC_OBJECT_VOUT ) { /* Look for the default filter configuration */ p_vout->psz_filter_chain = var_CreateGetStringCommand( p_vout, "vout-filter" ); /* Apply video filter2 objects on the first vout */ p_vout->psz_vf2 = var_CreateGetStringCommand( p_vout, "video-filter" ); } else { /* continue the parent's filter chain */ char *psz_tmp; /* Ugly hack to jump to our configuration chain */ p_vout->psz_filter_chain = ((vout_thread_t *)p_parent)->psz_filter_chain; p_vout->psz_filter_chain
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -