0, -1);
}
+static void
+ds_reset(GstVaapiDeinterlaceState *ds)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS(ds->buffers); i++)
+ gst_buffer_replace(&ds->buffers[i], NULL);
+ ds->buffers_index = 0;
+ ds->num_surfaces = 0;
+ ds->deint = FALSE;
+ ds->tff = FALSE;
+}
+
+static void
+ds_add_buffer(GstVaapiDeinterlaceState *ds, GstBuffer *buf)
+{
+ gst_buffer_replace(&ds->buffers[ds->buffers_index], buf);
+ ds->buffers_index = (ds->buffers_index + 1) % G_N_ELEMENTS(ds->buffers);
+}
+
+static inline GstBuffer *
+ds_get_buffer(GstVaapiDeinterlaceState *ds, guint index)
+{
+ const guint n = ds->buffers_index + G_N_ELEMENTS(ds->buffers) - index - 1;
+ return ds->buffers[n % G_N_ELEMENTS(ds->buffers)];
+}
+
+static void
+ds_set_surfaces(GstVaapiDeinterlaceState *ds)
+{
+ GstVaapiVideoMeta *meta;
+ guint i;
+
+ ds->num_surfaces = 0;
+ for (i = 0; i < G_N_ELEMENTS(ds->buffers); i++) {
+ GstBuffer * const buf = ds_get_buffer(ds, i);
+ if (!buf)
+ break;
+
+ meta = gst_buffer_get_vaapi_video_meta(buf);
+ ds->surfaces[ds->num_surfaces++] =
+ gst_vaapi_video_meta_get_surface(meta);
+ }
+}
+
static GstVaapiDeinterlaceMethod
get_next_deint_method(GstVaapiDeinterlaceMethod deint_method)
{
GstBuffer *outbuf)
{
GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
+ GstVaapiDeinterlaceState * const ds = &postproc->deinterlace_state;
GstVaapiVideoMeta *inbuf_meta, *outbuf_meta;
GstVaapiSurface *inbuf_surface, *outbuf_surface;
GstVaapiFilterStatus status;
tff = GST_BUFFER_FLAG_IS_SET(inbuf, GST_VIDEO_BUFFER_FLAG_TFF);
deint = is_interlaced_buffer(postproc, inbuf);
+ /* Drop references if deinterlacing conditions changed */
+ if (deint != ds->deint || (ds->num_surfaces > 0 && tff != ds->tff))
+ ds_reset(ds);
+ ds->deint = deint;
+ ds->tff = tff;
+
flags = gst_vaapi_video_meta_get_render_flags(inbuf_meta) &
~(GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD|
GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD);
if (deint) {
deint_flags = (tff ? GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD : 0);
+ if (tff)
+ deint_flags |= GST_VAAPI_DEINTERLACE_FLAG_TFF;
if (!set_best_deint_method(postproc, deint_flags, &deint_method))
goto error_op_deinterlace;
+
+ ds_set_surfaces(ds);
+ if (!gst_vaapi_filter_set_deinterlacing_references(postproc->filter,
+ ds->surfaces, ds->num_surfaces, NULL, 0))
+ goto error_op_deinterlace;
+
if (deint_method != postproc->deinterlace_method) {
GST_DEBUG("unsupported deinterlace-method %u. Using %u instead",
postproc->deinterlace_method, deint_method);
if (deint) {
deint_flags = (tff ? 0 : GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD);
+ if (tff)
+ deint_flags |= GST_VAAPI_DEINTERLACE_FLAG_TFF;
if (!gst_vaapi_filter_set_deinterlacing(postproc->filter,
deint_method, deint_flags))
goto error_op_deinterlace;
+
+ if (!gst_vaapi_filter_set_deinterlacing_references(postproc->filter,
+ ds->surfaces, ds->num_surfaces, NULL, 0))
+ goto error_op_deinterlace;
}
status = gst_vaapi_filter_process(postproc->filter, inbuf_surface,
}
gst_buffer_set_vaapi_video_meta(outbuf, outbuf_meta);
gst_vaapi_video_meta_unref(outbuf_meta);
+ ds_add_buffer(ds, inbuf);
return GST_FLOW_OK;
/* ERRORS */
typedef struct _GstVaapiPostproc GstVaapiPostproc;
typedef struct _GstVaapiPostprocClass GstVaapiPostprocClass;
+typedef struct _GstVaapiDeinterlaceState GstVaapiDeinterlaceState;
/**
* GstVaapiDeinterlaceMode:
GST_VAAPI_DEINTERLACE_MODE_DISABLED,
} GstVaapiDeinterlaceMode;
+/*
+ * GST_VAAPI_DEINTERLACE_MAX_REFERENCES:
+ *
+ * This represents the maximum number of VA surfaces we could keep as
+ * references for advanced deinterlacing.
+ *
+ * Note: if the upstream element is vaapidecode, then the maximum
+ * number of allowed surfaces used as references shall be less than
+ * the actual number of scratch surfaces used for decoding (4).
+ */
+#define GST_VAAPI_DEINTERLACE_MAX_REFERENCES 3
+
/**
* GstVaapiPostprocFlags:
* @GST_VAAPI_POSTPROC_FLAG_FORMAT: Pixel format conversion.
GST_VAAPI_POSTPROC_FLAG_SIZE = GST_VAAPI_POSTPROC_FLAG_CUSTOM,
} GstVaapiPostprocFlags;
+/*
+ * GstVaapiDeinterlaceState:
+ * @buffers: history buffer, maintained as a cyclic array
+ * @buffers_index: next free slot in the history buffer
+ * @surfaces: array of surfaces used as references
+ * @num_surfaces: number of active surfaces in that array
+ * @deint: flag: previous buffers were interlaced?
+ * @tff: flag: previous buffers were organized as top-field-first?
+ *
+ * Context used to maintain deinterlacing state.
+ */
+struct _GstVaapiDeinterlaceState {
+ GstBuffer *buffers[GST_VAAPI_DEINTERLACE_MAX_REFERENCES];
+ guint buffers_index;
+ GstVaapiSurface *surfaces[GST_VAAPI_DEINTERLACE_MAX_REFERENCES];
+ guint num_surfaces;
+ guint deint : 1;
+ guint tff : 1;
+};
+
struct _GstVaapiPostproc {
/*< private >*/
GstBaseTransform parent_instance;
/* Deinterlacing */
GstVaapiDeinterlaceMode deinterlace_mode;
GstVaapiDeinterlaceMethod deinterlace_method;
+ GstVaapiDeinterlaceState deinterlace_state;
GstClockTime field_duration;
guint is_raw_yuv : 1;