📄 vout_subpictures.c
字号:
( p_region->fmt.i_sar_den * p_fmt->i_sar_num ) ) { for( k = 0; k < SCALE_SIZE; k++ ) { pi_scale_width[k] = pi_scale_width[ k ] * (int64_t)p_region->fmt.i_sar_num * p_fmt->i_sar_den / p_region->fmt.i_sar_den / p_fmt->i_sar_num; pi_subpic_x[k] = p_subpic->i_x * pi_scale_width[ k ] / 1000; } } /* Load the scaling module when needed */ if( !p_spu->p_scale ) { bool b_scale_used = false; for( k = 0; k < SCALE_SIZE; k++ ) { const int i_scale_w = pi_scale_width[k]; const int i_scale_h = pi_scale_height[k]; if( ( i_scale_w > 0 && i_scale_w != 1000 ) || ( i_scale_h > 0 && i_scale_h != 1000 ) ) b_scale_used = true; } if( b_scale_used ) SpuRenderCreateAndLoadScale( p_spu ); } for( ; p_region != NULL; p_region = p_region->p_next ) SpuRenderRegion( p_spu, p_pic_dst, p_pic_src, p_subpic, p_region, i_scale_width_orig, i_scale_height_orig, pi_subpic_x, pi_scale_width, pi_scale_height, p_fmt ); } 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, bool b_paused ){ int i_index, i_channel; subpicture_t *p_subpic = NULL; subpicture_t *p_ephemer; mtime_t ephemer_date; /* Run subpicture filters */ filter_chain_SubFilter( p_spu->p_chain, display_date ); /* 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 ) && !( p_spu->p_subpicture[i_index].b_pausable && b_paused ) ) { /* 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, bool b_locked ){ int i_subpic; /* subpicture index */ subpicture_t *p_subpic = NULL; /* first free subpicture */ if( !b_locked ) 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; } } if( !b_locked ) 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++; break; case SPU_CHANNEL_CLEAR: i = (int)va_arg( args, int ); SpuClearChannel( p_spu, i, false ); 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; vlc_mutex_lock( &p_spu->subpicture_lock ); p_spu->b_force_palette = false; p_spu->b_force_crop = false; if( var_Get( p_object, "highlight", &val ) || !val.b_bool ) { vlc_mutex_unlock( &p_spu->subpicture_lock ); return; } p_spu->b_force_crop = 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 = true; } vlc_mutex_unlock( &p_spu->subpicture_lock ); 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 ){ (void)psz_var; (void)oldval; (void)newval; 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 ){ (void)p_filter; subpicture_t *p_subpic = (subpicture_t *)malloc(sizeof(subpicture_t)); if( !p_subpic ) return NULL; memset( p_subpic, 0, sizeof(subpicture_t) ); p_subpic->b_absolute = 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( !p_picture ) return NULL; 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 ){ (void)p_filter; if( p_pic ) { free( p_pic->p_data_orig ); free( p_pic ); }}static int SubFilterCallback( vlc_object_t *p_object, char const *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data ){ VLC_UNUSED(p_object); VLC_UNUSED(oldval); VLC_UNUSED(newval); VLC_UNUSED(psz_var); spu_t *p_spu = (spu_t *)p_data; vlc_mutex_lock( &p_spu->subpicture_lock ); filter_chain_Reset( p_spu->p_chain, NULL, NULL ); spu_ParseChain( p_spu ); vlc_mutex_unlock( &p_spu->subpicture_lock ); return VLC_SUCCESS;}static int sub_filter_allocation_init( filter_t *p_filter, void *p_data ){ spu_t *p_spu = (spu_t *)p_data; p_filter->pf_sub_buffer_new = sub_new_buffer; p_filter->pf_sub_buffer_del = sub_del_buffer; filter_owner_sys_t *p_sys = malloc( sizeof(filter_owner_sys_t) ); if( !p_sys ) return VLC_EGENERIC; p_filter->p_owner = p_sys; spu_Control( p_spu, SPU_CHANNEL_REGISTER, &p_sys->i_channel ); p_sys->p_spu = p_spu; return VLC_SUCCESS;}static void sub_filter_allocation_clear( filter_t *p_filter ){ filter_owner_sys_t *p_sys = p_filter->p_owner; SpuClearChannel( p_sys->p_spu, p_sys->i_channel, true ); free( p_filter->p_owner );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -