📄 vout_subpictures.c
字号:
} } /* If no free subpicture could be found */ if( p_subpic == NULL ) { msg_Err( p_spu, "subpicture heap is full" ); vlc_mutex_unlock( &p_spu->subpicture_lock ); return NULL; } /* Copy subpicture information, set some default values */ memset( p_subpic, 0, sizeof(subpicture_t) ); p_subpic->i_status = RESERVED_SUBPICTURE; p_subpic->b_absolute = true; p_subpic->b_pausable = false; p_subpic->b_fade = false; p_subpic->i_alpha = 0xFF; p_subpic->p_region = NULL; p_subpic->pf_render = NULL; p_subpic->pf_destroy = NULL; p_subpic->p_sys = NULL; vlc_mutex_unlock( &p_spu->subpicture_lock ); p_subpic->pf_create_region = __spu_CreateRegion; p_subpic->pf_make_region = __spu_MakeRegion; p_subpic->pf_destroy_region = __spu_DestroyRegion; return p_subpic;}/** * Remove a subpicture from the heap * * This function frees a previously reserved subpicture. * It is meant to be used when the construction of a picture aborted. * This function does not need locking since reserved subpictures are ignored * by the spu. */void spu_DestroySubpicture( spu_t *p_spu, subpicture_t *p_subpic ){ /* Get lock */ vlc_mutex_lock( &p_spu->subpicture_lock ); /* There can be race conditions so we need to check the status */ if( p_subpic->i_status == FREE_SUBPICTURE ) { vlc_mutex_unlock( &p_spu->subpicture_lock ); return; } /* Check if status is valid */ if( ( p_subpic->i_status != RESERVED_SUBPICTURE ) && ( p_subpic->i_status != READY_SUBPICTURE ) ) { msg_Err( p_spu, "subpicture %p has invalid status %d", p_subpic, p_subpic->i_status ); } 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_RenderSubpictures: render a subpicture list ***************************************************************************** * This function renders all sub picture units in the list. *****************************************************************************/static void SpuRenderCreateBlend( spu_t *p_spu, vlc_fourcc_t i_chroma, int i_aspect ){ filter_t *p_blend; assert( !p_spu->p_blend ); p_spu->p_blend = p_blend = vlc_custom_create( p_spu, sizeof(filter_t), VLC_OBJECT_GENERIC, "blend" ); if( !p_blend ) return; es_format_Init( &p_blend->fmt_in, VIDEO_ES, 0 ); es_format_Init( &p_blend->fmt_out, VIDEO_ES, 0 ); p_blend->fmt_out.video.i_x_offset = 0; p_blend->fmt_out.video.i_y_offset = 0; p_blend->fmt_out.video.i_chroma = i_chroma; p_blend->fmt_out.video.i_aspect = i_aspect; /* The blend module will be loaded when needed with the real * input format */ p_blend->p_module = NULL; /* */ vlc_object_attach( p_blend, p_spu );}static void SpuRenderUpdateBlend( spu_t *p_spu, int i_out_width, int i_out_height, const video_format_t *p_in_fmt ){ filter_t *p_blend = p_spu->p_blend; assert( p_blend ); /* */ if( p_blend->p_module && p_blend->fmt_in.video.i_chroma != p_in_fmt->i_chroma ) { /* The chroma is not the same, we need to reload the blend module * XXX to match the old behaviour just test !p_blend->fmt_in.video.i_chroma */ module_Unneed( p_blend, p_blend->p_module ); p_blend->p_module = NULL; } /* */ p_blend->fmt_in.video = *p_in_fmt; /* */ p_blend->fmt_out.video.i_width = p_blend->fmt_out.video.i_visible_width = i_out_width; p_blend->fmt_out.video.i_height = p_blend->fmt_out.video.i_visible_height = i_out_height; /* */ if( !p_blend->p_module ) p_blend->p_module = module_Need( p_blend, "video blending", 0, 0 );}static void SpuRenderCreateAndLoadText( spu_t *p_spu, int i_width, int i_height ){ filter_t *p_text; assert( !p_spu->p_text ); p_spu->p_text = p_text = vlc_custom_create( p_spu, sizeof(filter_t), VLC_OBJECT_GENERIC, "spu text" ); if( !p_text ) return; es_format_Init( &p_text->fmt_in, VIDEO_ES, 0 ); es_format_Init( &p_text->fmt_out, VIDEO_ES, 0 ); p_text->fmt_out.video.i_width = p_text->fmt_out.video.i_visible_width = i_width; p_text->fmt_out.video.i_height = p_text->fmt_out.video.i_visible_height = i_height; p_text->pf_sub_buffer_new = spu_new_buffer; p_text->pf_sub_buffer_del = spu_del_buffer; vlc_object_attach( p_text, p_spu ); /* FIXME TOCHECK shouldn't module_Need( , , psz_modulename, false ) do the * same than these 2 calls ? */ char *psz_modulename = var_CreateGetString( p_spu, "text-renderer" ); if( psz_modulename && *psz_modulename ) { p_text->p_module = module_Need( p_text, "text renderer", psz_modulename, true ); } free( psz_modulename ); if( !p_text->p_module ) p_text->p_module = module_Need( p_text, "text renderer", NULL, false );}static filter_t *CreateAndLoadScale( vlc_object_t *p_obj, vlc_fourcc_t i_chroma ){ filter_t *p_scale; p_scale = vlc_custom_create( p_obj, sizeof(filter_t), VLC_OBJECT_GENERIC, "scale" ); if( !p_scale ) return NULL; es_format_Init( &p_scale->fmt_in, VIDEO_ES, 0 ); p_scale->fmt_in.video.i_chroma = i_chroma; p_scale->fmt_in.video.i_width = p_scale->fmt_in.video.i_height = 32; es_format_Init( &p_scale->fmt_out, VIDEO_ES, 0 ); p_scale->fmt_out.video.i_chroma = i_chroma; p_scale->fmt_out.video.i_width = p_scale->fmt_out.video.i_height = 16; p_scale->pf_vout_buffer_new = spu_new_video_buffer; p_scale->pf_vout_buffer_del = spu_del_video_buffer; vlc_object_attach( p_scale, p_obj ); p_scale->p_module = module_Need( p_scale, "video filter2", 0, 0 ); return p_scale;}static void SpuRenderCreateAndLoadScale( spu_t *p_spu ){ /* FIXME: We'll also be using it for YUVA and RGBA blending ... */ assert( !p_spu->p_scale ); assert( !p_spu->p_scale_yuvp ); p_spu->p_scale = CreateAndLoadScale( VLC_OBJECT(p_spu), VLC_FOURCC('Y','U','V','A') ); p_spu->p_scale_yuvp = p_spu->p_scale_yuvp = CreateAndLoadScale( VLC_OBJECT(p_spu), VLC_FOURCC('Y','U','V','P') );}static void SpuRenderText( spu_t *p_spu, bool *pb_rerender_text, subpicture_t *p_subpic, subpicture_region_t *p_region, int i_min_scale_ratio ){ assert( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') ); if( !p_spu->p_text || !p_spu->p_text->p_module ) goto exit; /* Setup 3 variables which can be used to render * time-dependent text (and effects). The first indicates * the total amount of time the text will be on screen, * the second the amount of time it has already been on * screen (can be a negative value as text is layed out * before it is rendered) and the third is a feedback * variable from the renderer - if the renderer sets it * then this particular text is time-dependent, eg. the * visual progress bar inside the text in karaoke and the * text needs to be rendered multiple times in order for * the effect to work - we therefore need to return the * region to its original state at the end of the loop, * instead of leaving it in YUVA or YUVP. * Any renderer which is unaware of how to render * time-dependent text can happily ignore the variables * and render the text the same as usual - it should at * least show up on screen, but the effect won't change * the text over time. */ /* FIXME why these variables are recreated every time and not * when text renderer module was created ? */ var_Create( p_spu->p_text, "spu-duration", VLC_VAR_TIME ); var_Create( p_spu->p_text, "spu-elapsed", VLC_VAR_TIME ); var_Create( p_spu->p_text, "text-rerender", VLC_VAR_BOOL ); var_Create( p_spu->p_text, "scale", VLC_VAR_INTEGER ); var_SetTime( p_spu->p_text, "spu-duration", p_subpic->i_stop - p_subpic->i_start ); var_SetTime( p_spu->p_text, "spu-elapsed", mdate() - p_subpic->i_start ); var_SetBool( p_spu->p_text, "text-rerender", false ); var_SetInteger( p_spu->p_text, "scale", i_min_scale_ratio ); if( p_spu->p_text->pf_render_html && p_region->psz_html ) { p_spu->p_text->pf_render_html( p_spu->p_text, p_region, p_region ); } else if( p_spu->p_text->pf_render_text ) { p_spu->p_text->pf_render_text( p_spu->p_text, p_region, p_region ); } *pb_rerender_text = var_GetBool( p_spu->p_text, "text-rerender" ); var_Destroy( p_spu->p_text, "spu-duration" ); var_Destroy( p_spu->p_text, "spu-elapsed" ); var_Destroy( p_spu->p_text, "text-rerender" ); var_Destroy( p_spu->p_text, "scale" );exit: p_region->i_align |= SUBPICTURE_RENDERED;}static void SpuRenderRegion( spu_t *p_spu, picture_t *p_pic_dst, picture_t *p_pic_src, subpicture_t *p_subpic, subpicture_region_t *p_region, const int i_scale_width_orig, const int i_scale_height_orig, const int pi_subpic_x[SCALE_SIZE], const int pi_scale_width[SCALE_SIZE], const int pi_scale_height[SCALE_SIZE], const video_format_t *p_fmt ){ video_format_t fmt_original; bool b_rerender_text; bool b_restore_format = false; int i_fade_alpha; int i_x_offset; int i_y_offset; int i_scale_idx; int i_inv_scale_x; int i_inv_scale_y; filter_t *p_scale; vlc_assert_locked( &p_spu->subpicture_lock ); fmt_original = p_region->fmt; b_rerender_text = false; if( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') ) { SpuRenderText( p_spu, &b_rerender_text, p_subpic, p_region, __MIN(i_scale_width_orig, i_scale_height_orig) ); b_restore_format = b_rerender_text; /* Check if the rendering has failed ... */ if( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') ) goto exit; } if( p_region->i_align & SUBPICTURE_RENDERED ) { /* We are using a region which come from rendered text */ i_scale_idx = SCALE_TEXT; i_inv_scale_x = i_scale_width_orig; i_inv_scale_y = i_scale_height_orig; } else { i_scale_idx = SCALE_DEFAULT; i_inv_scale_x = 1000; i_inv_scale_y = 1000; } i_x_offset = (p_region->i_x + pi_subpic_x[ i_scale_idx ]) * i_inv_scale_x / 1000; i_y_offset = (p_region->i_y + p_subpic->i_y) * i_inv_scale_y / 1000; /* Force palette if requested * FIXME b_force_palette and b_force_crop are applied to all subpictures using palette * instead of only the right one (being the dvd spu). */ const bool b_using_palette = p_region->fmt.i_chroma == VLC_FOURCC('Y','U','V','P'); const bool b_force_palette = b_using_palette && p_spu->b_force_palette; const bool b_force_crop = b_force_palette && p_spu->b_force_crop; if( b_force_palette ) { /* It looks so wrong I won't comment * p_palette->palette is [256][4] with a int i_entries * p_spu->palette is [4][4] * */ p_region->fmt.p_palette->i_entries = 4; memcpy( p_region->fmt.p_palette->palette, p_spu->palette, 4*sizeof(uint32_t) ); } if( b_using_palette ) p_scale = p_spu->p_scale_yuvp; else p_scale = p_spu->p_scale; if( p_scale && ( ( pi_scale_width[i_scale_idx] > 0 && pi_scale_width[i_scale_idx] != 1000 ) || ( pi_scale_height[i_scale_idx] > 0 && pi_scale_height[i_scale_idx] != 1000 ) || ( b_force_palette ) ) ) { const unsigned i_dst_width = p_region->fmt.i_width * pi_scale_width[i_scale_idx] / 1000; const unsigned i_dst_height = p_region->fmt.i_height * pi_scale_height[i_scale_idx] / 1000; /* Destroy if cache is unusable */ if( p_region->p_cache ) { if( p_region->p_cache->fmt.i_width != i_dst_width || p_region->p_cache->fmt.i_height != i_dst_height || b_force_palette ) { p_subpic->pf_destroy_region( VLC_OBJECT(p_spu), p_region->p_cache ); p_region->p_cache = NULL; } } /* Scale if needed into cache */ if( !p_region->p_cache ) { picture_t *p_pic; p_scale->fmt_in.video = p_region->fmt; p_scale->fmt_out.video = p_region->fmt; p_region->p_cache = p_subpic->pf_create_region( VLC_OBJECT(p_spu),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -