📄 vout_subpictures.c
字号:
int i_crop_y = p_spu->i_crop_y * i_scale_height / 1000; int i_crop_width = p_spu->i_crop_width * i_scale_width / 1000; int i_crop_height = p_spu->i_crop_height * i_scale_height/1000; /* Find the intersection */ if( i_crop_x + i_crop_width <= i_x_offset || i_x_offset + (int)p_fmt->i_visible_width < i_crop_x || i_crop_y + i_crop_height <= i_y_offset || i_y_offset + (int)p_fmt->i_visible_height < i_crop_y ) { /* No intersection */ p_fmt->i_visible_width = p_fmt->i_visible_height = 0; } else { int i_x, i_y, i_x_end, i_y_end; i_x = __MAX( i_crop_x, i_x_offset ); i_y = __MAX( i_crop_y, i_y_offset ); i_x_end = __MIN( i_crop_x + i_crop_width, i_x_offset + (int)p_fmt->i_visible_width ); i_y_end = __MIN( i_crop_y + i_crop_height, i_y_offset + (int)p_fmt->i_visible_height ); p_fmt->i_x_offset = i_x - i_x_offset; p_fmt->i_y_offset = i_y - i_y_offset; p_fmt->i_visible_width = i_x_end - i_x; p_fmt->i_visible_height = i_y_end - i_y; i_x_offset = i_x; i_y_offset = i_y; } } /* Update the output picture size */ p_spu->p_blend->fmt_out.video.i_width = p_spu->p_blend->fmt_out.video.i_visible_width = p_fmt->i_width; p_spu->p_blend->fmt_out.video.i_height = p_spu->p_blend->fmt_out.video.i_visible_height = p_fmt->i_height; if( p_subpic->b_fade ) { mtime_t i_fade_start = ( p_subpic->i_stop + p_subpic->i_start ) / 2; mtime_t i_now = mdate(); if( i_now >= i_fade_start && p_subpic->i_stop > i_fade_start ) { i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) / ( p_subpic->i_stop - i_fade_start ); } } p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst, p_pic_src, &p_region->picture, i_x_offset, i_y_offset, i_fade_alpha * p_subpic->i_alpha / 255 ); p_region = p_region->p_next; } p_subpic = p_subpic->p_next; } vlc_mutex_unlock( &p_spu->subpicture_lock );}/***************************************************************************** * spu_SortSubpictures: find the subpictures to display ***************************************************************************** * This function parses all subpictures and decides which ones need to be * displayed. 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 also check for ephemer DVD subpictures (subpictures that have * to be removed if a newer one is available), which makes it a lot * more difficult to guess if a subpicture has to be rendered or not. *****************************************************************************/subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date ){ int i_index, i_channel; subpicture_t *p_subpic = NULL; subpicture_t *p_ephemer; mtime_t ephemer_date; /* Run subpicture filters */ for( i_index = 0; i_index < p_spu->i_filter; i_index++ ) { subpicture_t *p_subpic_filter; p_subpic_filter = p_spu->pp_filter[i_index]-> pf_sub_filter( p_spu->pp_filter[i_index], display_date ); if( p_subpic_filter ) { spu_DisplaySubpicture( p_spu, p_subpic_filter ); } } /* We get an easily parsable chained list of subpictures which * ends with NULL since p_subpic was initialized to NULL. */ for( i_channel = 0; i_channel < p_spu->i_channel; i_channel++ ) { p_ephemer = 0; ephemer_date = 0; for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ ) { if( p_spu->p_subpicture[i_index].i_channel != i_channel || p_spu->p_subpicture[i_index].i_status != READY_SUBPICTURE ) { continue; } if( display_date && display_date < p_spu->p_subpicture[i_index].i_start ) { /* Too early, come back next monday */ continue; } if( p_spu->p_subpicture[i_index].i_start > ephemer_date ) ephemer_date = p_spu->p_subpicture[i_index].i_start; if( display_date > p_spu->p_subpicture[i_index].i_stop && ( !p_spu->p_subpicture[i_index].b_ephemer || p_spu->p_subpicture[i_index].i_stop > p_spu->p_subpicture[i_index].i_start ) ) { /* Too late, destroy the subpic */ spu_DestroySubpicture( p_spu, &p_spu->p_subpicture[i_index] ); continue; } /* If this is an ephemer subpic, add it to our list */ if( p_spu->p_subpicture[i_index].b_ephemer ) { p_spu->p_subpicture[i_index].p_next = p_ephemer; p_ephemer = &p_spu->p_subpicture[i_index]; continue; } p_spu->p_subpicture[i_index].p_next = p_subpic; p_subpic = &p_spu->p_subpicture[i_index]; } /* If we found ephemer subpictures, check if they have to be * displayed or destroyed */ while( p_ephemer != NULL ) { subpicture_t *p_tmp = p_ephemer; p_ephemer = p_ephemer->p_next; if( p_tmp->i_start < ephemer_date ) { /* Ephemer subpicture has lived too long */ spu_DestroySubpicture( p_spu, p_tmp ); } else { /* Ephemer subpicture can still live a bit */ p_tmp->p_next = p_subpic; p_subpic = p_tmp; } } } return p_subpic;}/***************************************************************************** * SpuClearChannel: clear an spu channel ***************************************************************************** * This function destroys the subpictures which belong to the spu channel * corresponding to i_channel_id. *****************************************************************************/static void SpuClearChannel( spu_t *p_spu, int i_channel ){ int i_subpic; /* subpicture index */ subpicture_t *p_subpic = NULL; /* first free subpicture */ vlc_mutex_lock( &p_spu->subpicture_lock ); for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ ) { p_subpic = &p_spu->p_subpicture[i_subpic]; if( p_subpic->i_status == FREE_SUBPICTURE || ( p_subpic->i_status != RESERVED_SUBPICTURE && p_subpic->i_status != READY_SUBPICTURE ) ) { continue; } if( p_subpic->i_channel == i_channel ) { while( p_subpic->p_region ) { subpicture_region_t *p_region = p_subpic->p_region; p_subpic->p_region = p_region->p_next; spu_DestroyRegion( p_spu, p_region ); } if( p_subpic->pf_destroy ) p_subpic->pf_destroy( p_subpic ); p_subpic->i_status = FREE_SUBPICTURE; } } vlc_mutex_unlock( &p_spu->subpicture_lock );}/***************************************************************************** * spu_ControlDefault: default methods for the subpicture unit control. *****************************************************************************/static int spu_vaControlDefault( spu_t *p_spu, int i_query, va_list args ){ int *pi, i; switch( i_query ) { case SPU_CHANNEL_REGISTER: pi = (int *)va_arg( args, int * ); if( pi ) *pi = p_spu->i_channel++; msg_Dbg( p_spu, "Registering subpicture channel, ID: %i", p_spu->i_channel - 1 ); break; case SPU_CHANNEL_CLEAR: i = (int)va_arg( args, int ); SpuClearChannel( p_spu, i ); break; default: msg_Dbg( p_spu, "control query not supported" ); return VLC_EGENERIC; } return VLC_SUCCESS;}/***************************************************************************** * Object variables callbacks *****************************************************************************//***************************************************************************** * UpdateSPU: update subpicture settings ***************************************************************************** * This function is called from CropCallback and at initialization time, to * retrieve crop information from the input. *****************************************************************************/static void UpdateSPU( spu_t *p_spu, vlc_object_t *p_object ){ vlc_value_t val; p_spu->b_force_palette = VLC_FALSE; p_spu->b_force_crop = VLC_FALSE; if( var_Get( p_object, "highlight", &val ) || !val.b_bool ) return; p_spu->b_force_crop = VLC_TRUE; var_Get( p_object, "x-start", &val ); p_spu->i_crop_x = val.i_int; var_Get( p_object, "y-start", &val ); p_spu->i_crop_y = val.i_int; var_Get( p_object, "x-end", &val ); p_spu->i_crop_width = val.i_int - p_spu->i_crop_x; var_Get( p_object, "y-end", &val ); p_spu->i_crop_height = val.i_int - p_spu->i_crop_y; if( var_Get( p_object, "menu-palette", &val ) == VLC_SUCCESS ) { memcpy( p_spu->palette, val.p_address, 16 ); p_spu->b_force_palette = VLC_TRUE; } msg_Dbg( p_object, "crop: %i,%i,%i,%i, palette forced: %i", p_spu->i_crop_x, p_spu->i_crop_y, p_spu->i_crop_width, p_spu->i_crop_height, p_spu->b_force_palette );}/***************************************************************************** * CropCallback: called when the highlight properties are changed ***************************************************************************** * This callback is called from the input thread when we need cropping *****************************************************************************/static int CropCallback( vlc_object_t *p_object, char const *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data ){ UpdateSPU( (spu_t *)p_data, p_object ); return VLC_SUCCESS;}/***************************************************************************** * Buffers allocation callbacks for the filters *****************************************************************************/static subpicture_t *sub_new_buffer( filter_t *p_filter ){ filter_owner_sys_t *p_sys = p_filter->p_owner; subpicture_t *p_subpicture = spu_CreateSubpicture( p_sys->p_spu ); if( p_subpicture ) p_subpicture->i_channel = p_sys->i_channel; return p_subpicture;}static void sub_del_buffer( filter_t *p_filter, subpicture_t *p_subpic ){ filter_owner_sys_t *p_sys = p_filter->p_owner; spu_DestroySubpicture( p_sys->p_spu, p_subpic );}static subpicture_t *spu_new_buffer( filter_t *p_filter ){ subpicture_t *p_subpic = (subpicture_t *)malloc(sizeof(subpicture_t)); memset( p_subpic, 0, sizeof(subpicture_t) ); p_subpic->b_absolute = VLC_TRUE; p_subpic->pf_create_region = __spu_CreateRegion; p_subpic->pf_make_region = __spu_MakeRegion; p_subpic->pf_destroy_region = __spu_DestroyRegion; return p_subpic;}static void spu_del_buffer( filter_t *p_filter, subpicture_t *p_subpic ){ while( p_subpic->p_region ) { subpicture_region_t *p_region = p_subpic->p_region; p_subpic->p_region = p_region->p_next; p_subpic->pf_destroy_region( VLC_OBJECT(p_filter), p_region ); } free( p_subpic );}static picture_t *spu_new_video_buffer( filter_t *p_filter ){ picture_t *p_picture = malloc( sizeof(picture_t) ); if( vout_AllocatePicture( p_filter, p_picture, p_filter->fmt_out.video.i_chroma, p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height, p_filter->fmt_out.video.i_aspect ) != VLC_SUCCESS ) { free( p_picture ); return NULL; } p_picture->pf_release = RegionPictureRelease; return p_picture;}static void spu_del_video_buffer( filter_t *p_filter, picture_t *p_pic ){ if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig ); if( p_pic ) free( p_pic );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -