📄 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-2004 VideoLAN * $Id: video_output.c 11112 2005-05-22 16:18:46Z zorglub $ * * 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include <stdlib.h> /* free() */#include <vlc/vlc.h>#ifdef HAVE_SYS_TIMES_H# include <sys/times.h>#endif#include "vlc_video.h"#include "video_output.h"#include "vlc_spu.h"#include <vlc/input.h> /* for input_thread_t and i_pts_delay */#include "vlc_playlist.h"#if defined( SYS_DARWIN )#include "darwin_specific.h"#endif/***************************************************************************** * Local prototypes *****************************************************************************/static int InitThread ( vout_thread_t * );static void RunThread ( vout_thread_t * );static void ErrorThread ( vout_thread_t * );static void EndThread ( vout_thread_t * );static void DestroyThread ( vout_thread_t * );static void AspectRatio ( int, int *, int * );static int BinaryLog ( uint32_t );static void MaskToShift ( int *, int *, uint32_t );static void InitWindowSize ( vout_thread_t *, int *, int * );/* 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 * );/* From vout_intf.c */int vout_Snapshot( vout_thread_t *, picture_t * );/***************************************************************************** * 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 ){ if( !p_fmt ) { /* Reattach video output to input before bailing out */ if( p_vout ) { vlc_object_t *p_playlist; p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); if( p_playlist ) { spu_Attach( p_vout->p_spu, p_this, VLC_FALSE ); vlc_object_detach( p_vout ); vlc_object_attach( p_vout, p_playlist ); vlc_object_release( p_playlist ); } else { msg_Dbg( p_this, "cannot find playlist, destroying vout" ); vlc_object_detach( p_vout ); vout_Destroy( p_vout ); } } return NULL; } /* If a video output was provided, lock it, otherwise look for one. */ if( p_vout ) { vlc_object_yield( p_vout ); } else { p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT, FIND_CHILD ); if( !p_vout ) { playlist_t *p_playlist; p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); if( p_playlist ) { vlc_mutex_lock( &p_playlist->gc_lock ); p_vout = vlc_object_find( p_playlist, VLC_OBJECT_VOUT, FIND_CHILD ); /* only first children of p_input for unused vout */ if( p_vout && p_vout->p_parent != p_playlist ) { vlc_object_release( p_vout ); p_vout = NULL; } vlc_mutex_unlock( &p_playlist->gc_lock ); vlc_object_release( p_playlist ); } } } /* If we now have a video output, check it has the right properties */ if( p_vout ) { char *psz_filter_chain; vlc_value_t val; /* 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 = VLC_FALSE; } if( psz_filter_chain ) free( psz_filter_chain ); } if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) || ( p_vout->fmt_render.i_height != p_fmt->i_height ) || ( p_vout->fmt_render.i_chroma != p_fmt->i_chroma ) || ( p_vout->fmt_render.i_aspect != p_fmt->i_aspect && !p_vout->b_override_aspect ) || p_vout->b_filter_change ) { /* We are not interested in this format, close this vout */ vlc_object_detach( p_vout ); vlc_object_release( p_vout ); vout_Destroy( p_vout ); p_vout = NULL; } else { /* This video output is cool! Hijack it. */ vlc_object_detach( p_vout ); spu_Attach( p_vout->p_spu, p_this, VLC_TRUE ); vlc_object_attach( p_vout, p_this ); vlc_object_release( 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 */ char * psz_plugin; 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; /* Allocate descriptor */ p_vout = vlc_object_create( p_parent, VLC_OBJECT_VOUT ); if( p_vout == NULL ) { msg_Err( p_parent, "out of memory" ); 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 = 0; p_vout->render.i_gmask = 0; p_vout->render.i_bmask = 0; 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 = 0; p_vout->p_parent_intf = 0; /* Initialize locks */ vlc_mutex_init( p_vout, &p_vout->picture_lock ); vlc_mutex_init( p_vout, &p_vout->change_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, VLC_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 ); p_vout->b_override_aspect = VLC_FALSE; /* 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 ) { var_Get( p_vout, "aspect-ratio", &val ); /* Check whether the user tried to override aspect ratio */ if( val.psz_string ) { unsigned int i_new_aspect = i_aspect; char *psz_parser = strchr( val.psz_string, ':' ); if( psz_parser ) { *psz_parser++ = '\0'; i_new_aspect = atoi( val.psz_string ) * VOUT_ASPECT_FACTOR / atoi( psz_parser ); } else { i_new_aspect = VOUT_ASPECT_FACTOR * atof( val.psz_string ); } free( val.psz_string ); if( i_new_aspect && i_new_aspect != i_aspect ) { int i_aspect_x, i_aspect_y; AspectRatio( i_new_aspect, &i_aspect_x, &i_aspect_y ); msg_Dbg( p_vout, "overriding source aspect ratio to %i:%i", i_aspect_x, i_aspect_y ); p_vout->render.i_aspect = i_new_aspect; p_vout->b_override_aspect = VLC_TRUE; } } /* Look for the default filter configuration */ var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); var_Get( p_vout, "vout-filter", &val ); p_vout->psz_filter_chain = val.psz_string; if( p_vout->psz_filter_chain && *p_vout->psz_filter_chain && strchr( p_vout->psz_filter_chain, ',' ) && !strchr( p_vout->psz_filter_chain, ':') ) { msg_Info( p_vout, "Warning: you are using a deprecated syntax for " "vout-filter." ); msg_Info( p_vout, "You must now use ':' as separator instead of " "','." ); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -