[vlc-devel] [PATCH] video_output: blend subtitles with hw pics when taking a snaphost

Thomas Guillem thomas at gllm.fr
Fri Mar 2 12:07:20 CET 2018


Fixes #19892
---
 src/video_output/video_output.c | 76 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 73 insertions(+), 3 deletions(-)

diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index e1ae9f023a..32348e83a7 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -910,6 +910,59 @@ static int ThreadDisplayPreparePicture(vout_thread_t *vout, bool reuse, bool fra
     return VLC_SUCCESS;
 }
 
+static picture_t *ConvertRGBAndBlendBufferNew(filter_t *filter)
+{
+    return picture_NewFromFormat(&filter->fmt_out.video);
+}
+
+static picture_t *ConvertRGBAndBlend(vout_thread_t *vout, picture_t *pic,
+                                     subpicture_t *subpic)
+{
+    /* This function will convert the pic to RGB32 and blend the subpic to it.
+     * The returned pic can't be used to display since the chroma will be
+     * different than the "vout display" one, but it can be used for snapshots.
+     * */
+
+    assert(vout->p->spu_blend);
+
+    filter_owner_t owner = {
+        .video = {
+            .buffer_new = ConvertRGBAndBlendBufferNew,
+        },
+    };
+    filter_chain_t *filterc = filter_chain_NewVideo(vout, false, &owner);
+    if (!filterc)
+        return NULL;
+
+    es_format_t src = vout->p->spu_blend->fmt_out;
+    es_format_t dst = src;
+    dst.video.i_chroma = VLC_CODEC_RGB32;
+
+    if (filter_chain_AppendConverter(filterc, &src, &dst) != 0)
+    {
+        filter_chain_Delete(filterc);
+        return NULL;
+    }
+
+    picture_Hold(pic);
+    pic = filter_chain_VideoFilter(filterc, pic);
+    filter_chain_Delete(filterc);
+
+    if (pic)
+    {
+        filter_t *swblend = filter_NewBlend(VLC_OBJECT(vout), &dst.video);
+        if (swblend)
+        {
+            bool success = picture_BlendSubpicture(pic, swblend, subpic) > 0;
+            filter_DeleteBlend(swblend);
+            if (success)
+                return pic;
+        }
+        picture_Release(pic);
+    }
+    return NULL;
+}
+
 static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
 {
     vout_thread_sys_t *sys = vout->p;
@@ -1014,6 +1067,7 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
      */
     bool is_direct = vout->p->decoder_pool == vout->p->display_pool;
     picture_t *todisplay = filtered;
+    picture_t *snap_pic = todisplay;
     if (do_early_spu && subpic) {
         if (vout->p->spu_blend) {
             picture_t *blent = picture_pool_Get(vout->p->private_pool);
@@ -1022,9 +1076,20 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
                 picture_Copy(blent, filtered);
                 if (picture_BlendSubpicture(blent, vout->p->spu_blend, subpic)) {
                     picture_Release(todisplay);
-                    todisplay = blent;
+                    snap_pic = todisplay = blent;
                 } else
+                {
+                    /* Blending failed, likely because the picture is opaque or
+                     * read-only. Try to convert the opaque picture to a
+                     * software RGB32 one before blending it. */
+                    if (do_snapshot)
+                    {
+                        picture_t *copy = ConvertRGBAndBlend(vout, blent, subpic);
+                        if (copy)
+                            snap_pic = copy;
+                    }
                     picture_Release(blent);
+                }
             }
         }
         subpicture_Delete(subpic);
@@ -1050,14 +1115,19 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
         VideoFormatCopyCropAr(&direct->format, &todisplay->format);
         picture_Copy(direct, todisplay);
         picture_Release(todisplay);
-        todisplay = direct;
+        snap_pic = todisplay = direct;
     }
 
     /*
      * Take a snapshot if requested
      */
     if (do_snapshot)
-        vout_snapshot_Set(&vout->p->snapshot, &vd->source, todisplay);
+    {
+        assert(snap_pic);
+        vout_snapshot_Set(&vout->p->snapshot, &vd->source, snap_pic);
+        if (snap_pic != todisplay)
+            picture_Release(snap_pic);
+    }
 
     /* Render the direct buffer */
     vout_UpdateDisplaySourceProperties(vd, &todisplay->format);
-- 
2.11.0



More information about the vlc-devel mailing list