[vlc-devel] [PATCH] hw: vaapi: double framerate for Bob and X deint modes

Oliver Collyer ovcollyer at mac.com
Thu Jul 6 16:48:32 CEST 2017


(v3 following Victorien's comments)

This patch makes the Bob and X deinterlace modes output double the framerate under VAAPI, bringing it into line with DXVA2 and D3D11VA.

---
 modules/hw/vaapi/filters.c | 136 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 118 insertions(+), 18 deletions(-)

diff --git a/modules/hw/vaapi/filters.c b/modules/hw/vaapi/filters.c
index db3b3a84cb..5bbb022643 100644
--- a/modules/hw/vaapi/filters.c
+++ b/modules/hw/vaapi/filters.c
@@ -222,16 +222,19 @@ struct  deint_mode
 {
     char const                  name[5];
     VAProcDeinterlacingType     type;
+    bool                        b_double_rate;
 };
 
 static struct deint_mode const  deint_modes[] =
 {
-    { "x",     VAProcDeinterlacingMotionAdaptive },
-    { "x",     VAProcDeinterlacingMotionCompensated },
-    { "bob",   VAProcDeinterlacingBob },
-    { "mean",  VAProcDeinterlacingWeave }
+    { "x",     VAProcDeinterlacingMotionAdaptive,     true },
+    { "x",     VAProcDeinterlacingMotionCompensated,  true },
+    { "bob",   VAProcDeinterlacingBob,                true },
+    { "mean",  VAProcDeinterlacingWeave,              false }
 };
 
+#define METADATA_SIZE 3
+
 struct  deint_data
 {
     struct
@@ -247,6 +250,15 @@ struct  deint_data
         VASurfaceID *   surfaces;
         unsigned int    sz;
     } backward_refs, forward_refs;
+
+    struct
+    {
+        mtime_t date;
+        int     i_nb_fields;
+    } meta[METADATA_SIZE];
+
+    bool                b_double_rate;
+    unsigned int        cur_frame;
 };
 
 /********************
@@ -813,6 +825,20 @@ Deinterlace_UpdateHistory(struct deint_data * p_deint_data, picture_t * src)
 }
 
 static void
+Deinterlace_UpdateFilterParams(void * p_data, void * va_params)
+{
+    struct deint_data *const    p_deint_data = p_data;
+    VAProcFilterParameterBufferDeinterlacing *const      p_va_params = va_params;
+
+    p_va_params->flags =
+        p_deint_data->history.pp_cur_pic[0]->b_top_field_first ?
+        0 : VA_DEINTERLACING_BOTTOM_FIELD_FIRST;
+    if (p_deint_data->cur_frame ==
+        (p_deint_data->history.pp_cur_pic[0]->b_top_field_first ? 1 : 0))
+        p_va_params->flags |= VA_DEINTERLACING_BOTTOM_FIELD;
+}
+
+static void
 Deinterlace_UpdateReferenceFrames(void * p_data)
 {
     struct deint_data *const    p_deint_data = p_data;
@@ -842,10 +868,6 @@ Deinterlace_UpdatePipelineParams
 {
     struct deint_data *const    p_deint_data = p_data;
 
-    pipeline_param->filter_flags =
-        p_deint_data->history.pp_cur_pic[0]->b_top_field_first ?
-        0 : VA_DEINTERLACING_BOTTOM_FIELD_FIRST;
-
     pipeline_param->backward_references = p_deint_data->backward_refs.surfaces;
     pipeline_param->forward_references = p_deint_data->forward_refs.surfaces;
     pipeline_param->num_backward_references = p_deint_data->backward_refs.sz;
@@ -863,7 +885,8 @@ Deinterlace(filter_t * filter, picture_t * src)
         return NULL;
 
     picture_t *const    dest =
-        Filter(filter, src, NULL,
+        Filter(filter, src,
+               Deinterlace_UpdateFilterParams,
                Deinterlace_UpdateReferenceFrames,
                Deinterlace_UpdatePipelineParams);
 
@@ -873,6 +896,71 @@ Deinterlace(filter_t * filter, picture_t * src)
     return dest;
 }
 
+static picture_t *
+DeinterlaceX2(filter_t * filter, picture_t * src)
+{
+    filter_sys_t *const         filter_sys = filter->p_sys;
+    struct deint_data *const    p_deint_data = filter_sys->p_data;
+    const video_format_t *      fmt = &filter->fmt_out.video;
+
+    /* TODO: could use the meta array and calculation from deinterlace/common
+       but then it would also be appropriate to use the picture history array
+       too and the callback system...so a rewrite of this module basically.*/
+    for (unsigned int i = 1; i < METADATA_SIZE; ++i)
+        p_deint_data->meta[i-1] = p_deint_data->meta[i];
+    p_deint_data->meta[METADATA_SIZE-1].date        = src->date;
+    p_deint_data->meta[METADATA_SIZE-1].i_nb_fields = src->i_nb_fields;
+
+    mtime_t i_field_dur = 0;
+    unsigned int i = 0;
+    for ( ; i < METADATA_SIZE-1; i ++)
+        if (p_deint_data->meta[i].date > VLC_TS_INVALID)
+            break;
+    if (i < METADATA_SIZE-1) {
+        unsigned int i_fields_total = 0;
+        for (unsigned int j = i; j < METADATA_SIZE-1; ++j)
+            i_fields_total += p_deint_data->meta[j].i_nb_fields;
+        i_field_dur = (src->date - p_deint_data->meta[i].date) / i_fields_total;
+    }
+    else if (fmt->i_frame_rate_base)
+        i_field_dur = CLOCK_FREQ * fmt->i_frame_rate_base / fmt->i_frame_rate;
+
+    src = Deinterlace_UpdateHistory(p_deint_data, src);
+    if (p_deint_data->history.num_pics < p_deint_data->history.sz)
+        return NULL;
+
+    picture_t *dest[2] = {NULL, NULL};
+    for (i = 0; i < 2; ++i)
+    {
+        p_deint_data->cur_frame = i;
+        dest[i] = Filter(filter, src,
+                         Deinterlace_UpdateFilterParams,
+                         Deinterlace_UpdateReferenceFrames,
+                         Deinterlace_UpdatePipelineParams);
+        if (!dest[i])
+           goto error;
+
+        dest[i]->b_progressive = true;
+        dest[i]->i_nb_fields = 1;
+    }
+
+    dest[0]->p_next = dest[1];
+    dest[0]->date = src->date;
+    if (dest[0]->date > VLC_TS_INVALID)
+        dest[1]->date = dest[0]->date + i_field_dur;
+    else
+        dest[1]->date = VLC_TS_INVALID;
+
+    return dest[0];
+
+error:
+    for (i = 0; i < 2; ++i)
+        if (dest[i])
+            picture_Release(dest[i]);
+
+    return NULL;
+}
+
 static inline bool
 OpenDeinterlace_IsValidType(filter_t * filter,
                             VAProcDeinterlacingType const caps[],
@@ -888,7 +976,7 @@ OpenDeinterlace_IsValidType(filter_t * filter,
 
 static inline int
 OpenDeinterlace_GetMode(filter_t * filter, char const * deint_mode,
-                        VAProcDeinterlacingType * p_deint_mode,
+                        struct  deint_mode * p_deint_mode,
                         VAProcDeinterlacingType const caps[],
                         unsigned int num_caps)
 {
@@ -902,7 +990,7 @@ OpenDeinterlace_GetMode(filter_t * filter, char const * deint_mode,
                 if (OpenDeinterlace_IsValidType(filter, caps, num_caps,
                                                 deint_modes + i))
                 {
-                    *p_deint_mode = deint_modes[i].type;
+                    memcpy(p_deint_mode, &deint_modes[i], sizeof(*p_deint_mode));
                     msg_Dbg(filter, "using %s deinterlace method",
                             deint_modes[i].name);
                     return VLC_SUCCESS;
@@ -916,7 +1004,7 @@ OpenDeinterlace_GetMode(filter_t * filter, char const * deint_mode,
         if (OpenDeinterlace_IsValidType(filter, caps, num_caps,
                                         deint_modes + i))
         {
-            *p_deint_mode = deint_modes[i].type;
+            memcpy(p_deint_mode, &deint_modes[i], sizeof(*p_deint_mode));
             if (fallback)
                 msg_Info(filter, "%s algorithm not available, falling back to "
                          "%s algorithm", deint_mode, deint_modes[i].name);
@@ -939,7 +1027,8 @@ OpenDeinterlace_InitFilterParams(filter_t * filter, void * p_data,
                                  void ** pp_va_params,
                                  uint32_t * p_va_param_sz,
                                  uint32_t * p_num_va_params)
-{ VLC_UNUSED(p_data);
+{
+    struct deint_data *const    p_deint_data = p_data;
     filter_sys_t *const         filter_sys = filter->p_sys;
     VAProcDeinterlacingType     caps[VAProcDeinterlacingCount];
     unsigned int                num_caps = VAProcDeinterlacingCount;
@@ -951,12 +1040,12 @@ OpenDeinterlace_InitFilterParams(filter_t * filter, void * p_data,
                                            &caps, &num_caps))
         return VLC_EGENERIC;
 
-    VAProcDeinterlacingType     va_mode;
-    char *const                 psz_deint_mode =
+    struct deint_mode   deint_mode;
+    char *const         psz_deint_mode =
         var_InheritString(filter, "deinterlace-mode");
 
     int ret = OpenDeinterlace_GetMode(filter, psz_deint_mode,
-                                      &va_mode, caps, num_caps);
+                                      &deint_mode, caps, num_caps);
     free(psz_deint_mode);
     if (ret)
         return VLC_EGENERIC;
@@ -971,9 +1060,11 @@ OpenDeinterlace_InitFilterParams(filter_t * filter, void * p_data,
         return VLC_ENOMEM;
 
     p_va_param->type = VAProcFilterDeinterlacing;
-    p_va_param->algorithm = va_mode;
+    p_va_param->algorithm = deint_mode.type;
     *pp_va_params = p_va_param;
 
+    p_deint_data->b_double_rate = deint_mode.b_double_rate;
+
     return VLC_SUCCESS;
 }
 
@@ -1027,7 +1118,16 @@ OpenDeinterlace(vlc_object_t * obj)
              OpenDeinterlace_InitFilterParams, OpenDeinterlace_InitHistory))
         goto error;
 
-    filter->pf_video_filter = Deinterlace;
+    if (p_data->b_double_rate)
+        filter->pf_video_filter = DeinterlaceX2;
+    else
+        filter->pf_video_filter = Deinterlace;
+
+    for (unsigned int i = 0; i < METADATA_SIZE; ++i)
+    {
+        p_data->meta[i].date = VLC_TS_INVALID;
+        p_data->meta[i].i_nb_fields = 2;
+    }
 
     return VLC_SUCCESS;
 
-- 
2.11.0



More information about the vlc-devel mailing list