[vlc-devel] [PATCH] hw: vaapi: double framerate for Bob and X deint modes
Oliver Collyer
ovcollyer at mac.com
Wed Jul 5 20:00:51 CEST 2017
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 | 133 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 116 insertions(+), 17 deletions(-)
diff --git a/modules/hw/vaapi/filters.c b/modules/hw/vaapi/filters.c
index db3b3a84cb..d6dd50a7e6 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;
@@ -873,6 +895,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;
+ if (i)
+ dest[i-1]->p_next = dest[i];
+ dest[i]->b_progressive = true;
+ dest[i]->i_nb_fields = 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 +975,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 +989,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 +1003,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 +1026,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 +1039,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 +1059,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 +1117,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