[vlc-devel] [RFC 1/7] subpictures: support rendering subpictures in display dimensions
Salah-Eddin Shaban
salah at videolan.org
Mon Feb 19 11:43:04 CET 2018
---
include/vlc_spu.h | 3 +-
include/vlc_subpicture.h | 13 ++++++++
include/vlc_vout_display.h | 1 +
modules/stream_out/transcode/video.c | 2 +-
src/misc/subpicture.c | 12 ++++++++
src/video_output/video_output.c | 26 +++++++++++-----
src/video_output/vout_subpictures.c | 59 +++++++++++++++++++++++++-----------
7 files changed, 89 insertions(+), 27 deletions(-)
diff --git a/include/vlc_spu.h b/include/vlc_spu.h
index dc8ea90fa6..496349f3dd 100644
--- a/include/vlc_spu.h
+++ b/include/vlc_spu.h
@@ -68,12 +68,13 @@ VLC_API void spu_PutSubpicture( spu_t *, subpicture_t * );
* subtitles visibles at the requested date.
*
* \param p_chroma_list is a list of supported chroma for the output (can be NULL)
+ * \param p_fmt_display is the format of the display. If identical to p_fmt_dst, subpictures will be rendered inside the video area.
* \param p_fmt_dst is the format of the picture on which the return subpicture will be rendered.
* \param p_fmt_src is the format of the original(source) video.
*
* The returned value if non NULL must be released by subpicture_Delete().
*/
-VLC_API subpicture_t * spu_Render( spu_t *, const vlc_fourcc_t *p_chroma_list, const video_format_t *p_fmt_dst, const video_format_t *p_fmt_src, mtime_t render_subtitle_date, mtime_t render_osd_date, bool ignore_osd );
+VLC_API subpicture_t * spu_Render( spu_t *, const vlc_fourcc_t *p_chroma_list, const video_format_t *p_fmt_display, const video_format_t *p_fmt_dst, const video_format_t *p_fmt_src, mtime_t render_subtitle_date, mtime_t render_osd_date, bool ignore_osd );
/**
* It registers a new SPU channel.
diff --git a/include/vlc_subpicture.h b/include/vlc_subpicture.h
index b9de52c049..76d1601073 100644
--- a/include/vlc_subpicture.h
+++ b/include/vlc_subpicture.h
@@ -61,6 +61,18 @@ struct subpicture_region_t
int i_x; /**< position of region, relative to alignment */
int i_y; /**< position of region, relative to alignment */
+
+ /**
+ * Original region position as set by the subpicture updater. Final position
+ * may be different. For example, constrained regions are translated to get
+ * their correct position inside the video area. Regions can also be moved
+ * to avoid overlapping.
+ */
+ int i_original_x;
+ int i_original_y;
+
+ bool b_constrained; /**< should be rendered within the video */
+
int i_align; /**< alignment flags of region */
int i_alpha; /**< transparency */
@@ -182,6 +194,7 @@ struct subpicture_t
/**@{*/
bool b_subtitle; /**< the picture is a movie subtitle */
bool b_absolute; /**< position is absolute */
+ bool b_constrained; /**< should be rendered within the video */
int i_original_picture_width; /**< original width of the movie */
int i_original_picture_height;/**< original height of the movie */
int i_alpha; /**< transparency */
diff --git a/include/vlc_vout_display.h b/include/vlc_vout_display.h
index ac2e1ca490..3dfa1b7077 100644
--- a/include/vlc_vout_display.h
+++ b/include/vlc_vout_display.h
@@ -132,6 +132,7 @@ typedef struct {
* needs to call vout_display_SendEventMouseMoved()
* or vout_display_SendEventMouseState() */
bool has_pictures_invalid; /* Will VOUT_DISPLAY_EVENT_PICTURES_INVALID be used */
+ bool constrained_spu; /* Can render subpictures only within video area */
const vlc_fourcc_t *subpicture_chromas; /* List of supported chromas for subpicture rendering. */
} vout_display_info_t;
diff --git a/modules/stream_out/transcode/video.c b/modules/stream_out/transcode/video.c
index 1a641bb929..0b6bb1c956 100644
--- a/modules/stream_out/transcode/video.c
+++ b/modules/stream_out/transcode/video.c
@@ -714,7 +714,7 @@ static void OutputFrame( sout_stream_t *p_stream, picture_t *p_pic, sout_stream_
fmt.i_y_offset = 0;
}
- subpicture_t *p_subpic = spu_Render( p_sys->p_spu, NULL, &fmt,
+ subpicture_t *p_subpic = spu_Render( p_sys->p_spu, NULL, &fmt, &fmt,
&id->p_decoder->fmt_out.video,
p_pic->date, p_pic->date, false );
diff --git a/src/misc/subpicture.c b/src/misc/subpicture.c
index fdf111fb69..4c5d45097a 100644
--- a/src/misc/subpicture.c
+++ b/src/misc/subpicture.c
@@ -170,6 +170,13 @@ void subpicture_Update( subpicture_t *p_subpicture,
p_upd->pf_update( p_subpicture, p_fmt_src, p_fmt_dst, i_ts );
+ /* These should probably be set in the subpicture updaters */
+ for( subpicture_region_t *r = p_subpicture->p_region; r; r = r->p_next )
+ {
+ r->i_original_x = r->i_x;
+ r->i_original_y = r->i_y;
+ }
+
video_format_Clean( &p_private->src );
video_format_Clean( &p_private->dst );
@@ -232,6 +239,9 @@ subpicture_region_t *subpicture_region_New( const video_format_t *p_fmt )
p_region->i_alpha = 0xff;
p_region->b_balanced_text = true;
+ /* render regions within video area by default */
+ p_region->b_constrained = true;
+
if( p_fmt->i_chroma == VLC_CODEC_TEXT )
return p_region;
@@ -311,6 +321,8 @@ subpicture_region_t* subpicture_region_Copy( subpicture_region_t *p_region_src )
p_region_dst->i_align = p_region_src->i_align;
p_region_dst->i_alpha = p_region_src->i_alpha;
+ p_region_dst->b_constrained = p_region_src->b_constrained;
+
p_region_dst->p_text = text_segment_Copy( p_region_src->p_text );
//Palette is already copied by subpicture_region_New, we just have to duplicate p_pixels
diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index 9108e876df..374d819e52 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -955,19 +955,29 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
const vlc_fourcc_t *subpicture_chromas;
video_format_t fmt_spu;
+ video_format_t fmt_display;
if (do_dr_spu) {
vout_display_place_t place;
vout_display_PlacePicture(&place, &vd->source, vd->cfg, false);
fmt_spu = vd->source;
- if (fmt_spu.i_width * fmt_spu.i_height < place.width * place.height) {
- fmt_spu.i_sar_num = vd->cfg->display.sar.num;
- fmt_spu.i_sar_den = vd->cfg->display.sar.den;
- fmt_spu.i_width =
- fmt_spu.i_visible_width = place.width;
- fmt_spu.i_height =
- fmt_spu.i_visible_height = place.height;
+
+ fmt_spu.i_sar_num = vd->cfg->display.sar.num;
+ fmt_spu.i_sar_den = vd->cfg->display.sar.den;
+ fmt_spu.i_width =
+ fmt_spu.i_visible_width = place.width;
+ fmt_spu.i_height =
+ fmt_spu.i_visible_height = place.height;
+
+ fmt_display = fmt_spu;
+ if( !vd->info.constrained_spu )
+ {
+ fmt_display.i_width =
+ fmt_display.i_visible_width = vd->cfg->display.width;
+ fmt_display.i_height =
+ fmt_display.i_visible_height = vd->cfg->display.height;
}
+
subpicture_chromas = vd->info.subpicture_chromas;
} else {
if (do_early_spu) {
@@ -996,7 +1006,7 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
video_format_t fmt_spu_rot;
video_format_ApplyRotation(&fmt_spu_rot, &fmt_spu);
subpicture_t *subpic = spu_Render(vout->p->spu,
- subpicture_chromas, &fmt_spu_rot,
+ subpicture_chromas, &fmt_display, &fmt_spu_rot,
&vd->source,
render_subtitle_date, render_osd_date,
do_snapshot);
diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c
index 1d654e4d4f..d81c1e76e7 100644
--- a/src/video_output/vout_subpictures.c
+++ b/src/video_output/vout_subpictures.c
@@ -693,6 +693,7 @@ static void SpuRenderRegion(spu_t *spu,
const bool crop_requested = (force_palette && sys->force_crop) ||
region->i_max_width || region->i_max_height;
bool changed_palette = false;
+ const bool b_constrained = region->b_constrained;
/* Compute the margin which is expressed in destination pixel unit
* The margin is applied only to subtitle and when no forced crop is
@@ -952,6 +953,7 @@ static void SpuRenderRegion(spu_t *spu,
dst->i_x = x_offset;
dst->i_y = y_offset;
dst->i_align = 0;
+ dst->b_constrained = b_constrained;
if (dst->p_picture)
picture_Release(dst->p_picture);
dst->p_picture = picture_Hold(region_picture);
@@ -992,6 +994,7 @@ static subpicture_t *SpuRenderSubpictures(spu_t *spu,
unsigned int i_subpicture,
subpicture_t **pp_subpicture,
const vlc_fourcc_t *chroma_list,
+ const video_format_t *fmt_display,
const video_format_t *fmt_dst,
const video_format_t *fmt_src,
mtime_t render_subtitle_date,
@@ -1021,8 +1024,8 @@ static subpicture_t *SpuRenderSubpictures(spu_t *spu,
if (!output)
return NULL;
output->i_order = pp_subpicture[i_subpicture - 1]->i_order;
- output->i_original_picture_width = fmt_dst->i_visible_width;
- output->i_original_picture_height = fmt_dst->i_visible_height;
+ output->i_original_picture_width = fmt_display->i_visible_width;
+ output->i_original_picture_height = fmt_display->i_visible_height;
subpicture_region_t **output_last_ptr = &output->p_region;
/* Allocate area array for subtitle overlap */
@@ -1066,21 +1069,32 @@ static subpicture_t *SpuRenderSubpictures(spu_t *spu,
sys->text->fmt_out.video.i_visible_height = subpic->i_original_picture_height;
}
- /* Render all regions
- * We always transform non absolute subtitle into absolute one on the
- * first rendering to allow good subtitle overlap support.
- */
+ /* Render all regions */
for (region = subpic->p_region; region != NULL; region = region->p_next) {
spu_area_t area;
+ region->i_x = region->i_original_x;
+ region->i_y = region->i_original_y;
+
+ /*
+ * Constrained regions should be translated inside the video area.
+ * This will be modified to take --align into account. Right now it assumes
+ * the video is centered horizontally and vertically within its window.
+ */
+ if( region->b_constrained )
+ {
+ region->i_x += (fmt_display->i_visible_width - fmt_dst->i_visible_width) / 2;
+ region->i_y += (fmt_display->i_visible_height - fmt_dst->i_visible_height) / 2;
+ }
+
/* Compute region scale AR */
video_format_t region_fmt = region->fmt;
if (region_fmt.i_sar_num <= 0 || region_fmt.i_sar_den <= 0) {
- const uint64_t i_sar_num = (uint64_t)fmt_dst->i_visible_width *
- fmt_dst->i_sar_num * subpic->i_original_picture_height;
- const uint64_t i_sar_den = (uint64_t)fmt_dst->i_visible_height *
- fmt_dst->i_sar_den * subpic->i_original_picture_width;
+ const uint64_t i_sar_num = (uint64_t)fmt_display->i_visible_width *
+ fmt_display->i_sar_num * subpic->i_original_picture_height;
+ const uint64_t i_sar_den = (uint64_t)fmt_display->i_visible_height *
+ fmt_display->i_sar_den * subpic->i_original_picture_width;
vlc_ureduce(®ion_fmt.i_sar_num, ®ion_fmt.i_sar_den,
i_sar_num, i_sar_den, 65536);
@@ -1090,9 +1104,9 @@ static subpicture_t *SpuRenderSubpictures(spu_t *spu,
* FIXME The current scaling ensure that the heights match, the width being
* cropped.
*/
- spu_scale_t scale = spu_scale_createq((uint64_t)fmt_dst->i_visible_height * fmt_dst->i_sar_den * region_fmt.i_sar_num,
- (uint64_t)subpic->i_original_picture_height * fmt_dst->i_sar_num * region_fmt.i_sar_den,
- fmt_dst->i_visible_height,
+ spu_scale_t scale = spu_scale_createq((uint64_t)fmt_display->i_visible_height * fmt_display->i_sar_den * region_fmt.i_sar_num,
+ (uint64_t)subpic->i_original_picture_height * fmt_display->i_sar_num * region_fmt.i_sar_den,
+ fmt_display->i_visible_height,
subpic->i_original_picture_height);
/* Check scale validity */
@@ -1102,7 +1116,7 @@ static subpicture_t *SpuRenderSubpictures(spu_t *spu,
/* */
SpuRenderRegion(spu, output_last_ptr, &area,
subpic, region, scale,
- chroma_list, fmt_dst,
+ chroma_list, fmt_display,
subtitle_area, subtitle_area_count,
subpic->b_subtitle ? render_subtitle_date : render_osd_date);
if (*output_last_ptr)
@@ -1118,8 +1132,6 @@ static subpicture_t *SpuRenderSubpictures(spu_t *spu,
subtitle_area[subtitle_area_count++] = area;
}
}
- if (subpic->b_subtitle && subpic->p_region)
- subpic->b_absolute = true;
}
/* */
@@ -1511,6 +1523,7 @@ void spu_PutSubpicture(spu_t *spu, subpicture_t *subpic)
subpicture_t *spu_Render(spu_t *spu,
const vlc_fourcc_t *chroma_list,
+ const video_format_t *fmt_display,
const video_format_t *fmt_dst,
const video_format_t *fmt_src,
mtime_t render_subtitle_date,
@@ -1583,9 +1596,20 @@ subpicture_t *spu_Render(spu_t *spu,
/* Updates the subpictures */
for (unsigned i = 0; i < subpicture_count; i++) {
subpicture_t *subpic = subpicture_array[i];
+
+ /* allow rendering outside the video area only if both the vout and the subpicture allow it */
+ bool b_constrained = video_format_IsSimilar( fmt_display, fmt_dst ) || subpic->b_constrained;
+
subpicture_Update(subpic,
- fmt_src, fmt_dst,
+ fmt_src, b_constrained ? fmt_dst : fmt_display,
subpic->b_subtitle ? render_subtitle_date : render_osd_date);
+
+ /* this should probably be set in the subpicture updaters */
+ for( subpicture_region_t *r = subpic->p_region; r; r = r->p_next )
+ r->b_constrained = b_constrained;
+
+ subpic->i_original_picture_width = fmt_display->i_visible_width;
+ subpic->i_original_picture_height = fmt_display->i_visible_height;
}
/* Now order the subpicture array
@@ -1596,6 +1620,7 @@ subpicture_t *spu_Render(spu_t *spu,
subpicture_t *render = SpuRenderSubpictures(spu,
subpicture_count, subpicture_array,
chroma_list,
+ fmt_display,
fmt_dst,
fmt_src,
render_subtitle_date,
--
2.13.6
More information about the vlc-devel
mailing list