📄 video_output.c
字号:
} else { /* continue the parent's filter chain */ char *psz_end; psz_end = strchr( ((vout_thread_t *)p_parent)->psz_filter_chain, ':' ); if( !psz_end ) psz_end = strchr( ((vout_thread_t *)p_parent)->psz_filter_chain, ',' ); if( psz_end && *(psz_end+1) ) p_vout->psz_filter_chain = strdup( psz_end+1 ); else p_vout->psz_filter_chain = NULL; } /* 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_plugin = val.psz_string; } else { /* the filter chain is a string list of filters separated by double * colons */ char *psz_end; psz_end = strchr( p_vout->psz_filter_chain, ':' ); if( !psz_end ) psz_end = strchr( p_vout->psz_filter_chain, ',' ); if( psz_end ) psz_plugin = strndup( p_vout->psz_filter_chain, psz_end - p_vout->psz_filter_chain ); else psz_plugin = strdup( p_vout->psz_filter_chain ); } /* Initialize the dimensions of the video window */ InitWindowSize( p_vout, &p_vout->i_window_width, &p_vout->i_window_height ); /* Create the vout thread */ p_vout->p_module = module_Need( p_vout, ( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ? "video filter" : "video output", psz_plugin, 0 ); if( psz_plugin ) free( psz_plugin ); if( p_vout->p_module == NULL ) { msg_Err( p_vout, "no suitable vout module" ); vlc_object_detach( p_vout ); vlc_object_destroy( 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 = ""; text.psz_string = _("Disable"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = "discard"; text.psz_string = _("Discard"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = "blend"; text.psz_string = _("Blend"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = "mean"; text.psz_string = _("Mean"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = "bob"; text.psz_string = _("Bob"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = "linear"; text.psz_string = _("Linear"); 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 ); if( val.psz_string ) 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, VLC_TRUE ) ) { msg_Err( p_vout, "out of memory" ); module_Unneed( p_vout, p_vout->p_module ); vlc_object_detach( p_vout ); vlc_object_destroy( p_vout ); return NULL; } if( p_vout->b_error ) { msg_Err( p_vout, "video output creation failed" ); /* Make sure the thread is destroyed */ p_vout->b_die = VLC_TRUE; vlc_thread_join( p_vout ); vlc_object_detach( p_vout ); vlc_object_destroy( p_vout ); return NULL; } return p_vout;}/***************************************************************************** * vout_Destroy: destroys a previously created video output ***************************************************************************** * Destroy a terminated thread. * The function will request a destruction of the specified thread. If pi_error * is NULL, it will return once the thread is destroyed. Else, it will be * update using one of the THREAD_* constants. *****************************************************************************/void vout_Destroy( vout_thread_t *p_vout ){ vlc_object_t *p_playlist; /* Request thread destruction */ p_vout->b_die = VLC_TRUE; vlc_thread_join( p_vout ); var_Destroy( p_vout, "intf-change" ); p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); if( p_vout->psz_filter_chain ) free( p_vout->psz_filter_chain ); /* Free structure */ vlc_object_destroy( p_vout ); /* If it was the last vout, tell the interface to show up */ if( p_playlist != NULL ) { vout_thread_t *p_another_vout = vlc_object_find( p_playlist, VLC_OBJECT_VOUT, FIND_ANYWHERE ); if( p_another_vout == NULL ) { vlc_value_t val; val.b_bool = VLC_TRUE; var_Set( p_playlist, "intf-show", val ); } else { vlc_object_release( p_another_vout ); } vlc_object_release( p_playlist ); }}/***************************************************************************** * 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. *****************************************************************************/static int InitThread( vout_thread_t *p_vout ){ int i, i_aspect_x, i_aspect_y; vlc_mutex_lock( &p_vout->change_lock );#ifdef STATS p_vout->c_loops = 0;#endif /* Initialize output method, it allocates direct buffers for us */ if( p_vout->pf_init( p_vout ) ) { vlc_mutex_unlock( &p_vout->change_lock ); 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 ); vlc_mutex_unlock( &p_vout->change_lock ); 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 ); vlc_mutex_unlock( &p_vout->change_lock ); 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_reduce( &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, chroma %4.4s, ar %i:%i, sar %i:%i", p_vout->output.i_width, p_vout->output.i_height, (char*)&p_vout->output.i_chroma, i_aspect_x, i_aspect_y, p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den ); /* Calculate shifts from system-updated masks */ MaskToShift( &p_vout->output.i_lrshift, &p_vout->output.i_rrshift, p_vout->output.i_rmask ); MaskToShift( &p_vout->output.i_lgshift, &p_vout->output.i_rgshift, p_vout->output.i_gmask ); MaskToShift( &p_vout->output.i_lbshift, &p_vout->output.i_rbshift, p_vout->output.i_bmask ); /* 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 ) && ( vout_ChromaCmp( p_vout->output.i_chroma, p_vout->render.i_chroma ) ) ) { /* 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; /* Choose the best module */ p_vout->chroma.p_module = module_Need( p_vout, "chroma", NULL, 0 ); if( p_vout->chroma.p_module == NULL ) { msg_Err( p_vout, "no chroma module for %4.4s to %4.4s", (char*)&p_vout->render.i_chroma, (char*)&p_vout->output.i_chroma ); p_vout->pf_end( p_vout ); vlc_mutex_unlock( &p_vout->change_lock ); 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; }/* XXX XXX mark thread ready */ 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( vout_thread_t *p_vout){ int i_index; /* index in heap */ int i_idle_loops = 0; /* loops without displaying a picture */ mtime_t current_date; /* current date */ mtime_t display_date; /* display date */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -