[vlc-devel] [PATCH] vout: snapshot: fix snapshots cropping

Romain Vimont rom at rom1v.com
Fri Nov 3 10:32:05 CET 2017


The snapshot picture was created using picture_Copy(), which does not
handle offsets. As a consequence, snapshots of cropped videos were
broken.

Therefore, add a function to easily clone the region of a picture into
a new picture_t, and use it to create the snapshot.

Fixes <https://trac.videolan.org/vlc/ticket/18970>.

Signed-off-by: Romain Vimont <rom at rom1v.com>
---
 include/vlc_picture.h       | 13 +++++++++++++
 src/misc/image.c            |  5 +++++
 src/misc/picture.c          | 39 +++++++++++++++++++++++++++++++++++++++
 src/video_output/snapshot.c |  7 ++++---
 4 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/include/vlc_picture.h b/include/vlc_picture.h
index e25374634f..151c8833b7 100644
--- a/include/vlc_picture.h
+++ b/include/vlc_picture.h
@@ -197,6 +197,19 @@ VLC_API void plane_CopyPixels( plane_t *p_dst, const plane_t *p_src );
 VLC_API void picture_Copy( picture_t *p_dst, const picture_t *p_src );
 
 /**
+ * This function will create a new picture containing the requested region.
+ *
+ * \param p_src pointer to the source picture.
+ * \param i_x_offset the region x offset.
+ * \param i_y_offset the region x offset.
+ * \param i_width the region with.
+ * \param i_height the region height.
+ */
+VLC_API picture_t *picture_CloneRegion( const picture_t *p_src,
+                                        int i_x_offset, int i_y_offset,
+                                        int i_width, int i_height );
+
+/**
  * This function will export a picture to an encoded bitstream.
  *
  * pp_image will contain the encoded bitstream in psz_format format.
diff --git a/src/misc/image.c b/src/misc/image.c
index aa5dd43a2d..7c3ad995c8 100644
--- a/src/misc/image.c
+++ b/src/misc/image.c
@@ -778,6 +778,11 @@ static filter_t *CreateFilter( vlc_object_t *p_this, const es_format_t *p_fmt_in
     es_format_Copy( &p_filter->fmt_in, p_fmt_in );
     es_format_Copy( &p_filter->fmt_out, p_fmt_in );
     video_format_Copy( &p_filter->fmt_out.video, p_fmt_out );
+
+    /* whatever the input offset, write at offset 0 in the target image */
+    p_filter->fmt_out.video.i_x_offset = 0;
+    p_filter->fmt_out.video.i_y_offset = 0;
+
     p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
     p_filter->p_module = module_need( p_filter, "video converter", NULL, false );
 
diff --git a/src/misc/picture.c b/src/misc/picture.c
index 59d0aaa359..4549514dfe 100644
--- a/src/misc/picture.c
+++ b/src/misc/picture.c
@@ -381,6 +381,45 @@ void picture_Copy( picture_t *p_dst, const picture_t *p_src )
     picture_CopyProperties( p_dst, p_src );
 }
 
+picture_t *picture_CloneRegion( const picture_t *p_src,
+                                int i_x_offset, int i_y_offset,
+                                int i_width, int i_height )
+{
+    /* allocate image with target height to avoid waste,
+     * but use the source width (with margins) to call memcpy() only once */
+    picture_t *p_dst = picture_New( p_src->format.i_chroma,
+                                    p_src->format.i_width,
+                                    i_height,
+                                    p_src->format.i_sar_num,
+                                    p_src->format.i_sar_den );
+    if( !p_dst )
+        return NULL;
+
+    picture_CopyProperties( p_dst, p_src );
+
+    /* only the left and right margins are kept in the target picture */
+    p_dst->format.i_visible_width = i_width;
+    p_dst->format.i_x_offset = i_x_offset;
+    p_dst->format.i_y_offset = 0;
+
+    const vlc_chroma_description_t *p_dsc =
+        vlc_fourcc_GetChromaDescription( p_src->format.i_chroma );
+    if( !p_dsc )
+        return NULL;
+
+    for( int i = 0; i < p_src->i_planes; ++i )
+    {
+        /* add (den - 1) to get the result rounded up */
+        int i_lines = (i_height + p_dsc->p[i].h.den - 1)
+                    * p_dsc->p[i].h.num / p_dsc->p[i].h.den;
+        int i_lines_offset = i_y_offset * p_dsc->p[i].h.num / p_dsc->p[i].h.den;
+        memcpy( p_dst->p[i].p_pixels,
+                p_src->p[i].p_pixels + i_lines_offset * p_src->p[i].i_pitch,
+                i_lines * p_src->p[i].i_pitch );
+    }
+
+    return p_dst;
+}
 
 /*****************************************************************************
  *
diff --git a/src/video_output/snapshot.c b/src/video_output/snapshot.c
index ceade008cc..3ad7cdf009 100644
--- a/src/video_output/snapshot.c
+++ b/src/video_output/snapshot.c
@@ -119,12 +119,13 @@ void vout_snapshot_Set(vout_snapshot_t *snap,
 
     vlc_mutex_lock(&snap->lock);
     while (snap->request_count > 0) {
-        picture_t *dup = picture_NewFromFormat(fmt);
+        picture_t *dup = picture_CloneRegion( picture, fmt->i_x_offset,
+                                                       fmt->i_y_offset,
+                                                       fmt->i_visible_width,
+                                                       fmt->i_visible_height );
         if (!dup)
             break;
 
-        picture_Copy(dup, picture);
-
         dup->p_next = snap->picture;
         snap->picture = dup;
         snap->request_count--;
-- 
2.11.0



More information about the vlc-devel mailing list