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

Oliver Collyer ovcollyer at mac.com
Thu Jul 6 08:30:59 CEST 2017


(v2 - fixed a mistake)

As discussed earlier on the list.

One thing I am not sure about with this patch is that it is not using the deinterlace/common meta array and calculation; instead it is using its own internal version.

The problem is if we were to use that shared code then logically we'd also want to use the picture history array and the callbacks too, which are part of the same "deinterlace_context" structure and then it becomes a bigger rewrite of this module....which was only recently written in the first place.

As such, I have placed a comment in the code suggesting a future rewrite/cleanup and it's of course up to you whether you merge this or not.

It makes a big different watching certain 1080i content though.

---
 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..7640df988f 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;
+
+    src = Deinterlace_UpdateHistory(p_deint_data, src);
+    if (p_deint_data->history.num_pics < p_deint_data->history.sz)
+        return NULL;
+
+    /* 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;
+
+    picture_t *dest[2] = {NULL, NULL};
+    for (unsigned int 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 (unsigned int 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