📄 vout_subpictures.c
字号:
&p_scale->fmt_out.video ); p_region->p_cache->p_next = p_region->p_next; if( p_scale->fmt_out.video.p_palette ) *p_scale->fmt_out.video.p_palette = *p_region->fmt.p_palette; vout_CopyPicture( p_spu, &p_region->p_cache->picture, &p_region->picture ); p_scale->fmt_out.video.i_width = i_dst_width; p_scale->fmt_out.video.i_height = i_dst_height; p_scale->fmt_out.video.i_visible_width = p_region->fmt.i_visible_width * pi_scale_width[ i_scale_idx ] / 1000; p_scale->fmt_out.video.i_visible_height = p_region->fmt.i_visible_height * pi_scale_height[ i_scale_idx ] / 1000; p_region->p_cache->fmt = p_scale->fmt_out.video; p_region->p_cache->i_x = p_region->i_x * pi_scale_width[ i_scale_idx ] / 1000; p_region->p_cache->i_y = p_region->i_y * pi_scale_height[ i_scale_idx ] / 1000; p_region->p_cache->i_align = p_region->i_align; p_region->p_cache->i_alpha = p_region->i_alpha; p_pic = NULL; if( p_scale->p_module ) p_pic = p_scale->pf_video_filter( p_scale, &p_region->p_cache->picture ); else msg_Err( p_spu, "scaling failed (module not loaded)" ); if( p_pic ) { p_region->p_cache->picture = *p_pic; free( p_pic ); } else { p_subpic->pf_destroy_region( VLC_OBJECT(p_spu), p_region->p_cache ); p_region->p_cache = NULL; } } /* And use the scaled picture */ if( p_region->p_cache ) { p_region = p_region->p_cache; fmt_original = p_region->fmt; } } if( p_region->i_align & SUBPICTURE_ALIGN_BOTTOM ) { i_y_offset = p_fmt->i_height - p_region->fmt.i_height - (p_subpic->i_y + p_region->i_y) * i_inv_scale_y / 1000; } else if ( !(p_region->i_align & SUBPICTURE_ALIGN_TOP) ) { i_y_offset = p_fmt->i_height / 2 - p_region->fmt.i_height / 2; } if( p_region->i_align & SUBPICTURE_ALIGN_RIGHT ) { i_x_offset = p_fmt->i_width - p_region->fmt.i_width - (pi_subpic_x[ i_scale_idx ] + p_region->i_x) * i_inv_scale_x / 1000; } else if ( !(p_region->i_align & SUBPICTURE_ALIGN_LEFT) ) { i_x_offset = p_fmt->i_width / 2 - p_region->fmt.i_width / 2; } if( p_subpic->b_absolute ) { i_x_offset = (p_region->i_x + pi_subpic_x[ i_scale_idx ] * pi_scale_width[ i_scale_idx ] / 1000) * i_inv_scale_x / 1000; i_y_offset = (p_region->i_y + p_subpic->i_y * pi_scale_height[ i_scale_idx ] / 1000) * i_inv_scale_y / 1000; } i_x_offset = __MAX( i_x_offset, 0 ); i_y_offset = __MAX( i_y_offset, 0 ); if( p_spu->i_margin != 0 && !b_force_crop ) { int i_diff = 0; int i_low = (i_y_offset - p_spu->i_margin) * i_inv_scale_y / 1000; int i_high = i_low + p_region->fmt.i_height; /* crop extra margin to keep within bounds */ if( i_low < 0 ) i_diff = i_low; if( i_high > (int)p_fmt->i_height ) i_diff = i_high - p_fmt->i_height; i_y_offset -= ( p_spu->i_margin * i_inv_scale_y / 1000 + i_diff ); } /* Force cropping if requested */ if( b_force_crop ) { video_format_t *p_fmt = &p_region->fmt; int i_crop_x = p_spu->i_crop_x * pi_scale_width[ i_scale_idx ] / 1000 * i_inv_scale_x / 1000; int i_crop_y = p_spu->i_crop_y * pi_scale_height[ i_scale_idx ] / 1000 * i_inv_scale_y / 1000; int i_crop_width = p_spu->i_crop_width * pi_scale_width[ i_scale_idx ] / 1000 * i_inv_scale_x / 1000; int i_crop_height = p_spu->i_crop_height * pi_scale_height[ i_scale_idx ] / 1000 * i_inv_scale_y / 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; } b_restore_format = true; } i_x_offset = __MAX( i_x_offset, 0 ); i_y_offset = __MAX( i_y_offset, 0 ); /* Compute alpha blend value */ i_fade_alpha = 255; 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 ); } } /* Update the blender */ SpuRenderUpdateBlend( p_spu, p_fmt->i_width, p_fmt->i_height, &p_region->fmt ); if( p_spu->p_blend->p_module ) { 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 * p_region->i_alpha / 65025 ); } else { msg_Err( p_spu, "blending %4.4s to %4.4s failed", (char *)&p_spu->p_blend->fmt_out.video.i_chroma, (char *)&p_spu->p_blend->fmt_out.video.i_chroma ); }exit: if( b_rerender_text ) { /* Some forms of subtitles need to be re-rendered more than * once, eg. karaoke. We therefore restore the region to its * pre-rendered state, so the next time through everything is * calculated again. */ p_region->picture.pf_release( &p_region->picture ); memset( &p_region->picture, 0, sizeof( picture_t ) ); p_region->i_align &= ~SUBPICTURE_RENDERED; } if( b_restore_format ) p_region->fmt = fmt_original;}void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt, picture_t *p_pic_dst, picture_t *p_pic_src, subpicture_t *p_subpic, int i_scale_width_orig, int i_scale_height_orig ){ int i_source_video_width; int i_source_video_height; subpicture_t *p_subpic_v; /* Get lock */ vlc_mutex_lock( &p_spu->subpicture_lock ); for( p_subpic_v = p_subpic; p_subpic_v != NULL && p_subpic_v->i_status != FREE_SUBPICTURE; p_subpic_v = p_subpic_v->p_next ) { if( p_subpic_v->pf_pre_render ) p_subpic_v->pf_pre_render( p_fmt, p_spu, p_subpic_v ); } if( i_scale_width_orig <= 0 ) i_scale_width_orig = 1000; if( i_scale_height_orig <= 0 ) i_scale_height_orig = 1000; i_source_video_width = p_fmt->i_width * 1000 / i_scale_width_orig; i_source_video_height = p_fmt->i_height * 1000 / i_scale_height_orig; /* Check i_status again to make sure spudec hasn't destroyed the subpic */ for( ; ( p_subpic != NULL ) && ( p_subpic->i_status != FREE_SUBPICTURE ); p_subpic = p_subpic->p_next ) { subpicture_region_t *p_region; int pi_scale_width[ SCALE_SIZE ]; int pi_scale_height[ SCALE_SIZE ]; int pi_subpic_x[ SCALE_SIZE ]; int k; /* If the source video and subtitles stream agree on the size of * the video then disregard all further references to the subtitle * stream. */ if( ( i_source_video_height == p_subpic->i_original_picture_height ) && ( i_source_video_width == p_subpic->i_original_picture_width ) ) { /* FIXME this looks wrong */ p_subpic->i_original_picture_height = 0; p_subpic->i_original_picture_width = 0; } for( k = 0; k < SCALE_SIZE ; k++ ) pi_subpic_x[ k ] = p_subpic->i_x; if( p_subpic->pf_update_regions ) { /* TODO do not reverse the scaling that was done before calling * spu_RenderSubpictures, just pass it along (or do it inside * spu_RenderSubpictures) */ video_format_t fmt_org = *p_fmt; fmt_org.i_width = fmt_org.i_visible_width = i_source_video_width; fmt_org.i_height = fmt_org.i_visible_height = i_source_video_height; p_subpic->pf_update_regions( &fmt_org, p_spu, p_subpic, mdate() ); } /* */ p_region = p_subpic->p_region; if( !p_region ) continue; /* Create the blending module */ if( !p_spu->p_blend ) SpuRenderCreateBlend( p_spu, p_fmt->i_chroma, p_fmt->i_aspect ); /* Load the text rendering module; it is possible there is a * text region somewhere in the subpicture other than the first * element in the region list, so just load it anyway as we'll * probably want it sooner or later. */ if( !p_spu->p_text ) SpuRenderCreateAndLoadText( p_spu, p_fmt->i_width, p_fmt->i_height ); if( p_spu->p_text ) { subpicture_region_t *p_text_region = p_subpic->p_region; /* Only overwrite the size fields if the region is still in * pre-rendered TEXT format. We have to traverse the subregion * list because if more than one subregion is present, the text * region isn't guarentteed to be the first in the list, and * only text regions use this flag. All of this effort assists * with the rescaling of text that has been rendered at native * resolution, rather than video resolution. */ while( p_text_region && p_text_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') ) { p_text_region = p_text_region->p_next; } if( p_text_region && ( ( p_text_region->i_align & SUBPICTURE_RENDERED ) == 0 ) ) { if( p_subpic->i_original_picture_height > 0 && p_subpic->i_original_picture_width > 0 ) { p_spu->p_text->fmt_out.video.i_width = p_spu->p_text->fmt_out.video.i_visible_width = p_subpic->i_original_picture_width; p_spu->p_text->fmt_out.video.i_height = p_spu->p_text->fmt_out.video.i_visible_height = p_subpic->i_original_picture_height; } else { p_spu->p_text->fmt_out.video.i_width = p_spu->p_text->fmt_out.video.i_visible_width = p_fmt->i_width; p_spu->p_text->fmt_out.video.i_height = p_spu->p_text->fmt_out.video.i_visible_height = p_fmt->i_height; } } /* XXX for text: * scale[] allows to pass from rendered size (by text module) to video output size */ pi_scale_width[SCALE_TEXT] = p_fmt->i_width * 1000 / p_spu->p_text->fmt_out.video.i_width; pi_scale_height[SCALE_TEXT]= p_fmt->i_height * 1000 / p_spu->p_text->fmt_out.video.i_height; } else { /* Just set a value to avoid using invalid memory while looping over the array */ pi_scale_width[SCALE_TEXT] = pi_scale_height[SCALE_TEXT]= 1000; } /* XXX for default: * scale[] allows to pass from native (either video or original) size to output size */ if( p_subpic->i_original_picture_height > 0 && p_subpic->i_original_picture_width > 0 ) { pi_scale_width[SCALE_DEFAULT] = p_fmt->i_width * 1000 / p_subpic->i_original_picture_width; pi_scale_height[SCALE_DEFAULT] = p_fmt->i_height * 1000 / p_subpic->i_original_picture_height; } else { pi_scale_width[ SCALE_DEFAULT ] = i_scale_width_orig; pi_scale_height[ SCALE_DEFAULT ] = i_scale_height_orig; } for( k = 0; k < SCALE_SIZE ; k++ ) { /* Case of both width and height being specified has been dealt * with above by instead rendering to an output pane of the * explicit dimensions specified - we don't need to scale it. */ if( p_subpic->i_original_picture_height > 0 && p_subpic->i_original_picture_width <= 0 ) { pi_scale_height[ k ] = pi_scale_height[ k ] * i_source_video_height / p_subpic->i_original_picture_height; pi_scale_width[ k ] = pi_scale_width[ k ] * i_source_video_height / p_subpic->i_original_picture_height; } } /* Set default subpicture aspect ratio */ if( !p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den ) { if( p_region->fmt.i_aspect != 0 ) { p_region->fmt.i_sar_den = p_region->fmt.i_aspect; p_region->fmt.i_sar_num = VOUT_ASPECT_FACTOR; } else { p_region->fmt.i_sar_den = p_fmt->i_sar_den; p_region->fmt.i_sar_num = p_fmt->i_sar_num; } } /* Take care of the aspect ratio */ if( ( p_region->fmt.i_sar_num * p_fmt->i_sar_den ) !=
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -