📄 video_output.c
字号:
= config_ChainCreate( &psz_tmp, &p_cfg, p_vout->psz_filter_chain ); config_ChainDestroy( p_cfg ); free( psz_tmp ); /* Create a video filter2 var ... but don't inherit values */ var_Create( p_vout, "video-filter", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); p_vout->psz_vf2 = var_GetString( p_vout, "video-filter" ); } var_AddCallback( p_vout, "video-filter", VideoFilter2Callback, NULL ); p_vout->p_vf2_chain = filter_chain_New( p_vout, "video filter2", false, video_filter_buffer_allocation_init, NULL, p_vout ); /* Choose the video output module */ if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain ) { var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); var_Get( p_vout, "vout", &val ); psz_parser = val.psz_string; } else { psz_parser = strdup( p_vout->psz_filter_chain ); p_vout->b_title_show = false; } /* Create the vout thread */ char* psz_tmp = config_ChainCreate( &psz_name, &p_cfg, psz_parser ); free( psz_parser ); free( psz_tmp ); p_vout->p_cfg = p_cfg; p_vout->p_module = module_Need( p_vout, ( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ? "video filter" : "video output", psz_name, p_vout->psz_filter_chain && *p_vout->psz_filter_chain ); free( psz_name ); if( p_vout->p_module == NULL ) { msg_Err( p_vout, "no suitable vout module" ); // FIXME it's ugly but that's exactly the function that need to be called. EndThread( p_vout ); vlc_object_detach( p_vout ); vlc_object_release( p_vout ); return NULL; } /* Create a few object variables for interface interaction */ var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE ); text.psz_string = _("Deinterlace"); var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL ); val.psz_string = (char *)""; text.psz_string = _("Disable"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = (char *)"discard"; text.psz_string = _("Discard"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = (char *)"blend"; text.psz_string = _("Blend"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = (char *)"mean"; text.psz_string = _("Mean"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = (char *)"bob"; text.psz_string = _("Bob"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = (char *)"linear"; text.psz_string = _("Linear"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = (char *)"x"; text.psz_string = (char *)"X"; var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); if( var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS ) { var_Set( p_vout, "deinterlace", val ); free( val.psz_string ); } var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL ); var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); text.psz_string = _("Filters"); var_Change( p_vout, "vout-filter", VLC_VAR_SETTEXT, &text, NULL ); var_AddCallback( p_vout, "vout-filter", FilterCallback, NULL ); /* Calculate delay created by internal caching */ p_input_thread = (input_thread_t *)vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_ANYWHERE ); if( p_input_thread ) { p_vout->i_pts_delay = p_input_thread->i_pts_delay; vlc_object_release( p_input_thread ); } else { p_vout->i_pts_delay = DEFAULT_PTS_DELAY; } if( vlc_thread_create( p_vout, "video output", RunThread, VLC_THREAD_PRIORITY_OUTPUT, true ) ) { module_Unneed( p_vout, p_vout->p_module ); vlc_object_release( p_vout ); return NULL; } vlc_object_set_destructor( p_vout, vout_Destructor ); if( p_vout->b_error ) { msg_Err( p_vout, "video output creation failed" ); vout_CloseAndRelease( p_vout ); return NULL; } return p_vout;}/***************************************************************************** * vout_Close: Close a vout created by vout_Create. ***************************************************************************** * You HAVE to call it on vout created by vout_Create before vlc_object_release. * You should NEVER call it on vout not obtained though vout_Create * (like with vout_Request or vlc_object_find.) * You can use vout_CloseAndRelease() as a convenient method. *****************************************************************************/void vout_Close( vout_thread_t *p_vout ){ assert( p_vout ); vlc_object_kill( p_vout ); vlc_thread_join( p_vout ); module_Unneed( p_vout, p_vout->p_module ); p_vout->p_module = NULL;}/* */static void vout_Destructor( vlc_object_t * p_this ){ vout_thread_t *p_vout = (vout_thread_t *)p_this; /* Make sure the vout was stopped first */ assert( !p_vout->p_module ); /* Destroy the locks */ vlc_mutex_destroy( &p_vout->picture_lock ); vlc_mutex_destroy( &p_vout->change_lock ); vlc_mutex_destroy( &p_vout->vfilter_lock ); free( p_vout->psz_filter_chain ); config_ChainDestroy( p_vout->p_cfg );#ifndef __APPLE__ vout_thread_t *p_another_vout; /* This is a dirty hack mostly for Linux, where there is no way to get the * GUI back if you closed it while playing video. This is solved in * Mac OS X, where we have this novelty called menubar, that will always * allow you access to the applications main functionality. They should try * that on linux sometime. */ p_another_vout = vlc_object_find( p_this->p_libvlc, VLC_OBJECT_VOUT, FIND_ANYWHERE ); if( p_another_vout == NULL ) var_SetBool( p_this->p_libvlc, "intf-show", true ); else vlc_object_release( p_another_vout );#endif}/***************************************************************************** * InitThread: initialize video output thread ***************************************************************************** * This function is called from RunThread and performs the second step of the * initialization. It returns 0 on success. Note that the thread's flag are not * modified inside this function. * XXX You have to enter it with change_lock taken. *****************************************************************************/static int ChromaCreate( vout_thread_t *p_vout );static void ChromaDestroy( vout_thread_t *p_vout );static bool ChromaIsEqual( const picture_heap_t *p_output, const picture_heap_t *p_render ){ if( !vout_ChromaCmp( p_output->i_chroma, p_render->i_chroma ) ) return false; if( p_output->i_chroma != FOURCC_RV15 && p_output->i_chroma != FOURCC_RV16 && p_output->i_chroma != FOURCC_RV24 && p_output->i_chroma != FOURCC_RV32 ) return true; return p_output->i_rmask == p_render->i_rmask && p_output->i_gmask == p_render->i_gmask && p_output->i_bmask == p_render->i_bmask;}static int InitThread( vout_thread_t *p_vout ){ int i, i_aspect_x, i_aspect_y;#ifdef STATS p_vout->c_loops = 0;#endif /* Initialize output method, it allocates direct buffers for us */ if( p_vout->pf_init( p_vout ) ) return VLC_EGENERIC; if( !I_OUTPUTPICTURES ) { msg_Err( p_vout, "plugin was unable to allocate at least " "one direct buffer" ); p_vout->pf_end( p_vout ); return VLC_EGENERIC; } if( I_OUTPUTPICTURES > VOUT_MAX_PICTURES ) { msg_Err( p_vout, "plugin allocated too many direct buffers, " "our internal buffers must have overflown." ); p_vout->pf_end( p_vout ); return VLC_EGENERIC; } msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES ); AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y ); msg_Dbg( p_vout, "picture in %ix%i (%i,%i,%ix%i), " "chroma %4.4s, ar %i:%i, sar %i:%i", p_vout->fmt_render.i_width, p_vout->fmt_render.i_height, p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset, p_vout->fmt_render.i_visible_width, p_vout->fmt_render.i_visible_height, (char*)&p_vout->fmt_render.i_chroma, i_aspect_x, i_aspect_y, p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den ); AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y ); msg_Dbg( p_vout, "picture user %ix%i (%i,%i,%ix%i), " "chroma %4.4s, ar %i:%i, sar %i:%i", p_vout->fmt_in.i_width, p_vout->fmt_in.i_height, p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset, p_vout->fmt_in.i_visible_width, p_vout->fmt_in.i_visible_height, (char*)&p_vout->fmt_in.i_chroma, i_aspect_x, i_aspect_y, p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den ); if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height ) { p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width = p_vout->output.i_width; p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height = p_vout->output.i_height; p_vout->fmt_out.i_x_offset = p_vout->fmt_out.i_y_offset = 0; p_vout->fmt_out.i_aspect = p_vout->output.i_aspect; p_vout->fmt_out.i_chroma = p_vout->output.i_chroma; } if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num ) { p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect * p_vout->fmt_out.i_height; p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR * p_vout->fmt_out.i_width; } vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den, p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 ); AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y ); msg_Dbg( p_vout, "picture out %ix%i (%i,%i,%ix%i), " "chroma %4.4s, ar %i:%i, sar %i:%i", p_vout->fmt_out.i_width, p_vout->fmt_out.i_height, p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset, p_vout->fmt_out.i_visible_width, p_vout->fmt_out.i_visible_height, (char*)&p_vout->fmt_out.i_chroma, i_aspect_x, i_aspect_y, p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den ); /* FIXME removed the need of both fmt_* and heap infos */ /* Calculate shifts from system-updated masks */ PictureHeapFixRgb( &p_vout->render ); VideoFormatImportRgb( &p_vout->fmt_render, &p_vout->render ); PictureHeapFixRgb( &p_vout->output ); VideoFormatImportRgb( &p_vout->fmt_out, &p_vout->output ); /* Check whether we managed to create direct buffers similar to * the render buffers, ie same size and chroma */ if( ( p_vout->output.i_width == p_vout->render.i_width ) && ( p_vout->output.i_height == p_vout->render.i_height ) && ( ChromaIsEqual( &p_vout->output, &p_vout->render ) ) ) { /* Cool ! We have direct buffers, we can ask the decoder to * directly decode into them ! Map the first render buffers to * the first direct buffers, but keep the first direct buffer * for memcpy operations */ p_vout->b_direct = 1; for( i = 1; i < VOUT_MAX_PICTURES; i++ ) { if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE && I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 && p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE ) { /* We have enough direct buffers so there's no need to * try to use system memory buffers. */ break; } PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ]; I_RENDERPICTURES++; } msg_Dbg( p_vout, "direct render, mapping " "render pictures 0-%i to system pictures 1-%i", VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 ); } else { /* Rats... Something is wrong here, we could not find an output * plugin able to directly render what we decode. See if we can * find a chroma plugin to do the conversion */ p_vout->b_direct = 0; if( ChromaCreate( p_vout ) ) { p_vout->pf_end( p_vout ); return VLC_EGENERIC; } msg_Dbg( p_vout, "indirect render, mapping " "render pictures 0-%i to system pictures %i-%i", VOUT_MAX_PICTURES - 1, I_OUTPUTPICTURES, I_OUTPUTPICTURES + VOUT_MAX_PICTURES - 1 ); /* Append render buffers after the direct buffers */ for( i = I_OUTPUTPICTURES; i < 2 * VOUT_MAX_PICTURES; i++ ) { PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ]; I_RENDERPICTURES++; /* Check if we have enough render pictures */ if( I_RENDERPICTURES == VOUT_MAX_PICTURES ) break; } } /* Link pictures back to their heap */ for( i = 0 ; i < I_RENDERPICTURES ; i++ ) { PP_RENDERPICTURE[ i ]->p_heap = &p_vout->render; } for( i = 0 ; i < I_OUTPUTPICTURES ; i++ ) { PP_OUTPUTPICTURE[ i ]->p_heap = &p_vout->output; } return VLC_SUCCESS;}/***************************************************************************** * RunThread: video output thread ***************************************************************************** * Video output thread. This function does only returns when the thread is * terminated. It handles the pictures arriving in the video heap and the * display device events. *****************************************************************************/static void* RunThread( vlc_object_t *p_this ){ vout_thread_t *p_vout = (vout_thread_t *)p_this; int i_idle_loops = 0; /* loops without displaying a picture */ picture_t * p_last_picture = NULL; /* last picture */ subpicture_t * p_subpic = NULL; /* subpicture pointer */ bool b_drop_late; int i_displayed = 0, i_lost = 0; /* * Initialize thread */ vlc_mutex_lock( &p_vout->change_lock ); p_vout->b_error = InitThread( p_vout ); b_drop_late = var_CreateGetBool( p_vout, "drop-late-frames" ); /* signal the creation of the vout */ vlc_thread_ready( p_vout ); if( p_vout->b_error ) { EndThread( p_vout ); vlc_mutex_unlock( &p_vout->change_lock ); return NULL; } vlc_object_lock( p_vout ); if( p_vout->b_title_show ) DisplayTitleOnOSD( p_vout ); /* * Main loop - it is not executed if an error occurred during * initialization */ while( vlc_object_alive( p_vout ) && !p_vout->b_error ) { /* Initialize loop variables */ const mtime_t current_date = mdate();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -