[vlc-devel] [PATCH] gstdecode: support alloc'ing vlc pictures with padding

Vikram Fugro vikram.fugro at gmail.com
Fri Mar 11 13:16:11 CET 2016


Allocate the output vlc pictures with dimensions padded,
as requested by the decoder (for alignments). This further
increases the chances of direct rendering.
---
 modules/codec/gstreamer/gstdecode.c                |  4 +-
 .../codec/gstreamer/gstvlcpictureplaneallocator.c  | 87 ++++++++++++++--------
 .../codec/gstreamer/gstvlcpictureplaneallocator.h  |  6 +-
 modules/codec/gstreamer/gstvlcvideopool.c          | 41 +++++++++-
 modules/codec/gstreamer/gstvlcvideopool.h          |  2 +
 modules/codec/gstreamer/gstvlcvideosink.c          | 16 +---
 6 files changed, 106 insertions(+), 50 deletions(-)

diff --git a/modules/codec/gstreamer/gstdecode.c b/modules/codec/gstreamer/gstdecode.c
index 42c6b27..ecaf2a2 100644
--- a/modules/codec/gstreamer/gstdecode.c
+++ b/modules/codec/gstreamer/gstdecode.c
@@ -179,6 +179,7 @@ static gboolean caps_handoff_cb( GstElement* p_ele, GstCaps *p_caps,
     VLC_UNUSED( p_ele );
     decoder_t *p_dec = p_data;
     decoder_sys_t *p_sys = p_dec->p_sys;
+    GstVideoAlignment align;
 
     msg_Info( p_dec, "got new caps %s", gst_caps_to_string( p_caps ));
 
@@ -189,8 +190,9 @@ static gboolean caps_handoff_cb( GstElement* p_ele, GstCaps *p_caps,
     }
 
     gst_vlc_dec_ensure_empty_queue( p_dec );
+    gst_video_alignment_reset( &align );
 
-    return gst_vlc_set_vout_fmt( &p_sys->vinfo, p_caps, p_dec );
+    return gst_vlc_set_vout_fmt( &p_sys->vinfo, &align, p_caps, p_dec );
 }
 
 /* Emitted by vlcvideosink for every buffer,
diff --git a/modules/codec/gstreamer/gstvlcpictureplaneallocator.c b/modules/codec/gstreamer/gstvlcpictureplaneallocator.c
index 4e827eb..089c549 100644
--- a/modules/codec/gstreamer/gstvlcpictureplaneallocator.c
+++ b/modules/codec/gstreamer/gstvlcpictureplaneallocator.c
@@ -197,8 +197,8 @@ bool gst_vlc_picture_plane_allocator_alloc(
         GstVlcPicturePlane *p_mem =
             (GstVlcPicturePlane*) g_slice_new0( GstVlcPicturePlane );
 
-        i_size = p_pic->p[ i_plane ].i_visible_pitch *
-            p_pic->p[ i_plane ].i_visible_lines;
+        i_size = p_pic->p[ i_plane ].i_pitch *
+            p_pic->p[ i_plane ].i_lines;
         i_max_size = p_pic->p[ i_plane ].i_pitch *
             p_pic->p[ i_plane ].i_lines;
         i_align = 0;
@@ -213,13 +213,14 @@ bool gst_vlc_picture_plane_allocator_alloc(
     return true;
 }
 
-bool gst_vlc_set_vout_fmt( GstVideoInfo *p_info, GstCaps *p_caps,
-        decoder_t *p_dec )
+bool gst_vlc_set_vout_fmt( GstVideoInfo *p_info, GstVideoAlignment *p_align,
+        GstCaps *p_caps, decoder_t *p_dec )
 {
     es_format_t *p_outfmt = &p_dec->fmt_out;
     video_format_t *p_voutfmt = &p_dec->fmt_out.video;
     GstStructure *p_str = gst_caps_get_structure( p_caps, 0 );
     vlc_fourcc_t i_chroma;
+    int i_padded_width, i_padded_height;
 
     i_chroma = p_outfmt->i_codec = vlc_fourcc_GetCodecFromString(
             VIDEO_ES,
@@ -230,10 +231,16 @@ bool gst_vlc_set_vout_fmt( GstVideoInfo *p_info, GstCaps *p_caps,
         return false;
     }
 
-    video_format_Setup( &p_dec->fmt_out.video, i_chroma,
-            GST_VIDEO_INFO_WIDTH( p_info ), GST_VIDEO_INFO_HEIGHT( p_info ),
+    i_padded_width = GST_VIDEO_INFO_WIDTH( p_info ) + p_align->padding_left +
+        p_align->padding_right;
+    i_padded_height = GST_VIDEO_INFO_HEIGHT( p_info ) + p_align->padding_top +
+        p_align->padding_bottom;
+
+    video_format_Setup( p_voutfmt, i_chroma, i_padded_width, i_padded_height,
             GST_VIDEO_INFO_WIDTH( p_info ), GST_VIDEO_INFO_HEIGHT( p_info ),
             GST_VIDEO_INFO_PAR_N( p_info ), GST_VIDEO_INFO_PAR_D( p_info ));
+    p_voutfmt->i_x_offset = p_align->padding_left;
+    p_voutfmt->i_y_offset = p_align->padding_top;
 
     p_voutfmt->i_frame_rate = GST_VIDEO_INFO_FPS_N( p_info );
     p_voutfmt->i_frame_rate_base = GST_VIDEO_INFO_FPS_D( p_info );
@@ -241,15 +248,19 @@ bool gst_vlc_set_vout_fmt( GstVideoInfo *p_info, GstCaps *p_caps,
     return true;
 }
 
-static bool gst_vlc_video_info_from_vout( GstVideoInfo *p_info, GstCaps *p_caps,
-        decoder_t *p_dec, picture_t *p_pic_info )
+static bool gst_vlc_video_info_from_vout( GstVideoInfo *p_info,
+        GstVideoAlignment *p_align, GstCaps *p_caps, decoder_t *p_dec,
+        picture_t *p_pic_info )
 {
+    const GstVideoFormatInfo *p_vinfo = p_info->finfo;
     picture_t *p_pic;
+    int i;
 
     /* Ensure the queue is empty */
     gst_vlc_dec_ensure_empty_queue( p_dec );
+    gst_video_info_align( p_info, p_align );
 
-    if( !gst_vlc_set_vout_fmt( p_info, p_caps, p_dec ))
+    if( !gst_vlc_set_vout_fmt( p_info, p_align, p_caps, p_dec ))
     {
         msg_Err( p_dec, "failed to set output format to vout" );
         return false;
@@ -265,52 +276,70 @@ static bool gst_vlc_video_info_from_vout( GstVideoInfo *p_info, GstCaps *p_caps,
         return false;
     }
 
+    /* reject if strides don't match */
+    for( i = 0; i < p_pic->i_planes; i++ )
+        if( p_info->stride[i] != p_pic->p[i].i_pitch )
+            goto strides_mismatch;
+
+    p_info->offset[0] = 0;
+    for( i = 1; i < p_pic->i_planes; i++ )
+    {
+        p_info->offset[i] = p_info->offset[i-1] +
+            p_pic->p[i-1].i_pitch * p_pic->p[i-1].i_lines;
+    }
+    GST_VIDEO_INFO_SIZE( p_info ) = p_info->offset[i-1] +
+        p_pic->p[i-1].i_pitch * p_pic->p[i-1].i_lines;
+
+    for( i = 0; i < p_pic->i_planes; i++ )
+    {
+        int i_v_edge, i_h_edge;
+
+        i_h_edge =
+            GST_VIDEO_FORMAT_INFO_SCALE_WIDTH( p_vinfo, i,
+                    p_align->padding_left);
+        i_v_edge =
+            GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT( p_vinfo, i,
+                    p_align->padding_top);
+
+        p_info->offset[i] += ( i_v_edge * p_info->stride[i] ) +
+            ( i_h_edge * GST_VIDEO_FORMAT_INFO_PSTRIDE( p_vinfo, i ));
+    }
+
     memcpy( p_pic_info, p_pic, sizeof( picture_t ));
     picture_Release( p_pic );
 
     return true;
+
+strides_mismatch:
+    msg_Err( p_dec, "strides mismatch" );
+    picture_Release( p_pic );
+    return false;
 }
 
 bool gst_vlc_picture_plane_allocator_query_format(
-        GstVlcPicturePlaneAllocator *p_allocator,
-        GstVideoInfo *p_info, GstCaps *p_caps )
+        GstVlcPicturePlaneAllocator *p_allocator, GstVideoInfo *p_info,
+        GstVideoAlignment *p_align, GstCaps *p_caps )
 {
     decoder_t *p_dec = p_allocator->p_dec;
     video_format_t v_fmt;
     picture_t *p_pic_info = &p_allocator->pic_info;
-    int i_plane, i_offset = 0, i_size = 0;
 
     /* Back up the original format; as this is just a query  */
     memcpy( &v_fmt, &p_dec->fmt_out.video, sizeof( video_format_t ));
 
-    if( !gst_vlc_video_info_from_vout( p_info, p_caps, p_dec, p_pic_info ))
+    if( !gst_vlc_video_info_from_vout( p_info, p_align, p_caps, p_dec,
+                p_pic_info ))
     {
         msg_Err( p_allocator->p_dec, "failed to get the vout info" );
         return false;
     }
 
-    //GST_VIDEO_INFO_N_PLANES( p_info ) = p_pic_info->i_planes;
-    for( i_plane = 0; i_plane < p_pic_info->i_planes; i_plane++ )
-    {
-        GST_VIDEO_INFO_PLANE_STRIDE( p_info, i_plane ) =
-            p_pic_info->p[ i_plane ].i_pitch;
-        GST_VIDEO_INFO_PLANE_OFFSET( p_info, i_plane ) = i_offset;
-        //i_offset += p_pic_info->p[ i_plane ].i_pitch *
-            //p_pic_info->p[ i_plane ].i_lines;
-        i_offset += p_pic_info->p[ i_plane ].i_visible_pitch *
-            p_pic_info->p[ i_plane ].i_visible_lines;
-        i_size += p_pic_info->p[ i_plane ].i_visible_pitch *
-            p_pic_info->p[ i_plane ].i_visible_lines;
-    }
-    GST_VIDEO_INFO_SIZE( p_info ) = i_size;
-
     /* Restore the original format; as this was just a query  */
     memcpy( &p_dec->fmt_out.video, &v_fmt, sizeof( video_format_t ));
 
     return true;
 }
 
-
 GstVlcPicturePlaneAllocator* gst_vlc_picture_plane_allocator_new(
         decoder_t *p_dec )
 {
diff --git a/modules/codec/gstreamer/gstvlcpictureplaneallocator.h b/modules/codec/gstreamer/gstvlcpictureplaneallocator.h
index bd27575..7607b4a 100644
--- a/modules/codec/gstreamer/gstvlcpictureplaneallocator.h
+++ b/modules/codec/gstreamer/gstvlcpictureplaneallocator.h
@@ -77,9 +77,9 @@ GstVlcPicturePlaneAllocator* gst_vlc_picture_plane_allocator_new(
         decoder_t *p_dec );
 bool gst_vlc_picture_plane_allocator_query_format(
         GstVlcPicturePlaneAllocator *p_gallocator, GstVideoInfo *p_info,
-        GstCaps *p_caps );
-bool gst_vlc_set_vout_fmt( GstVideoInfo *p_info, GstCaps *p_caps,
-        decoder_t *p_dec );
+        GstVideoAlignment *p_align, GstCaps *p_caps );
+bool gst_vlc_set_vout_fmt( GstVideoInfo *p_info, GstVideoAlignment *p_align,
+        GstCaps *p_caps, decoder_t *p_dec );
 void gst_vlc_dec_ensure_empty_queue( decoder_t* p_dec );
 bool gst_vlc_picture_plane_allocator_hold( GstVlcPicturePlaneAllocator
         *p_allocator, GstBuffer *p_buffer );
diff --git a/modules/codec/gstreamer/gstvlcvideopool.c b/modules/codec/gstreamer/gstvlcvideopool.c
index c22b501..f28b9bd 100644
--- a/modules/codec/gstreamer/gstvlcvideopool.c
+++ b/modules/codec/gstreamer/gstvlcvideopool.c
@@ -40,7 +40,7 @@ static const gchar** gst_vlc_video_pool_get_options (GstBufferPool *p_pool)
     VLC_UNUSED( p_pool );
 
     static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META,
-        NULL
+        GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT, NULL
     };
 
     return options;
@@ -52,6 +52,7 @@ static gboolean gst_vlc_video_pool_set_config( GstBufferPool *p_pool,
     GstVlcVideoPool *p_vpool = GST_VLC_VIDEO_POOL_CAST( p_pool );
     GstCaps *p_caps;
     GstVideoInfo info;
+    GstVideoAlignment align;
     guint size, min_buffers, max_buffers;
     GstAllocator *p_allocator;
     GstAllocationParams params;
@@ -59,7 +60,6 @@ static gboolean gst_vlc_video_pool_set_config( GstBufferPool *p_pool,
     if( !gst_buffer_pool_config_get_params( p_config, &p_caps, &size,
                 &min_buffers, &max_buffers ))
         goto wrong_config;
-
     if( p_caps == NULL )
         goto no_caps;
 
@@ -85,14 +85,37 @@ static gboolean gst_vlc_video_pool_set_config( GstBufferPool *p_pool,
         gst_buffer_pool_config_has_option( p_config,
                 GST_BUFFER_POOL_OPTION_VIDEO_META );
 
+    p_vpool->b_need_aligned =
+        gst_buffer_pool_config_has_option( p_config,
+                GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT );
+
+    if( p_vpool->b_need_aligned )
+    {
+        p_vpool->b_add_metavideo = true;
+        gst_buffer_pool_config_get_video_alignment( p_config, &align );
+    }
+    else
+         gst_video_alignment_reset( &align );
+
+    // FIXME: the gst decoders' min buffers may not be equal to the number
+    // of buffers it actually allocates. Also the max buffers here could
+    // be zero. Moreover even if it was right, need to check if it can be
+    // communicated to the vout (including the dpb_size it calculates in
+    // src/input/decoder.c).
+    p_vpool->p_dec->i_extra_picture_buffers = 16;
+
     if( !gst_vlc_picture_plane_allocator_query_format( p_vpool->p_allocator,
-                &info, p_caps))
+                &info, &align, p_caps))
         goto unknown_format;
 
+    if( p_vpool->b_need_aligned )
+        gst_buffer_pool_config_set_video_alignment( p_config, &align);
+
     if( p_vpool->p_caps )
         gst_caps_unref( p_vpool->p_caps );
     p_vpool->p_caps = gst_caps_ref( p_caps );
     p_vpool->info = info;
+    p_vpool->align = align;
 
     msg_Dbg( p_vpool->p_dec, "setting the following config on the pool: %s, \
             size: %lu, min buffers: %u, max buffers: %u", gst_caps_to_string( p_caps ),
@@ -206,6 +229,17 @@ static GstFlowReturn gst_vlc_video_pool_alloc_buffer( GstBufferPool *p_pool,
     return GST_FLOW_OK;
 }
 
+static gboolean gst_vlc_video_pool_start( GstBufferPool *p_pool )
+{
+    GstVlcVideoPool *p_vpool = GST_VLC_VIDEO_POOL_CAST( p_pool );
+
+    if( !gst_vlc_set_vout_fmt( &p_vpool->info, &p_vpool->align,
+                p_vpool->p_caps, p_vpool->p_dec ))
+        return FALSE;
+
+    return GST_BUFFER_POOL_CLASS( parent_class )->start( p_pool );
+}
+
 static void gst_vlc_video_pool_class_init( GstVlcVideoPoolClass *p_klass )
 {
     GObjectClass *p_gobject_class = ( GObjectClass* )p_klass;
@@ -213,6 +247,7 @@ static void gst_vlc_video_pool_class_init( GstVlcVideoPoolClass *p_klass )
 
     p_gobject_class->finalize = gst_vlc_video_pool_finalize;
 
+    p_gstbufferpool_class->start = gst_vlc_video_pool_start;
     p_gstbufferpool_class->get_options = gst_vlc_video_pool_get_options;
     p_gstbufferpool_class->set_config = gst_vlc_video_pool_set_config;
     p_gstbufferpool_class->alloc_buffer = gst_vlc_video_pool_alloc_buffer;
diff --git a/modules/codec/gstreamer/gstvlcvideopool.h b/modules/codec/gstreamer/gstvlcvideopool.h
index 721befd..373a566 100644
--- a/modules/codec/gstreamer/gstvlcvideopool.h
+++ b/modules/codec/gstreamer/gstvlcvideopool.h
@@ -51,7 +51,9 @@ struct _GstVlcVideoPool
 
     GstCaps *p_caps;
     GstVideoInfo info;
+    GstVideoAlignment align;
     bool b_add_metavideo;
+    bool b_need_aligned;
 
     decoder_t *p_dec;
 };
diff --git a/modules/codec/gstreamer/gstvlcvideosink.c b/modules/codec/gstreamer/gstvlcvideosink.c
index 5dfd8cd..6988e0d 100644
--- a/modules/codec/gstreamer/gstvlcvideosink.c
+++ b/modules/codec/gstreamer/gstvlcvideosink.c
@@ -208,7 +208,6 @@ static gboolean gst_vlc_video_sink_propose_allocation( GstBaseSink* p_bsink,
     gsize i_size;
 
     gst_query_parse_allocation (p_query, &p_caps, &b_need_pool);
-
     if( p_caps == NULL )
         goto no_caps;
 
@@ -219,18 +218,12 @@ static gboolean gst_vlc_video_sink_propose_allocation( GstBaseSink* p_bsink,
         if( !gst_video_info_from_caps( &info, p_caps ))
             goto invalid_caps;
 
-        if( !gst_vlc_picture_plane_allocator_query_format(
-                    (GstVlcPicturePlaneAllocator*) p_vsink->p_allocator,
-                    &info, p_caps ))
-            goto invalid_format;
-
         p_pool = (GstBufferPool*) gst_vlc_video_sink_create_pool( p_vsink,
-                p_caps, info.size, 0 );
-
+                p_caps, info.size, 2 );
         if( p_pool == NULL )
             goto no_pool;
 
-        i_size = info.size;
+        i_size = GST_VIDEO_INFO_SIZE( &GST_VLC_VIDEO_POOL_CAST( p_pool )->info);
     }
 
     if( p_pool )
@@ -261,11 +254,6 @@ invalid_caps:
         msg_Err( p_vsink->p_dec, "invalid caps in allocation query" );
         return FALSE;
     }
-invalid_format:
-    {
-        msg_Err( p_vsink->p_dec, "vout query returned invalid format" );
-        return FALSE;
-    }
 }
 
 static GstFlowReturn gst_vlc_video_sink_chain( GstBaseSink *p_bsink,
-- 
2.5.0



More information about the vlc-devel mailing list