[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(&region_fmt.i_sar_num, &region_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