vaapipostproc: add support for advanced deinterlacing.

Add initial support for advanced deinterlacing. The history buffer
size is arbitrarily set to 3 references for now.
This commit is contained in:
Gwenole Beauchesne 2013-11-21 19:52:56 +01:00
parent 49e2d040fa
commit c8bea66d33
2 changed files with 101 additions and 0 deletions

View file

@ -371,6 +371,51 @@ append_output_buffer_metadata(GstBuffer *outbuf, GstBuffer *inbuf, guint flags)
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)
{
@ -409,6 +454,7 @@ gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
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;
@ -433,6 +479,12 @@ gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
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);
@ -451,8 +503,16 @@ gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
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);
@ -484,9 +544,15 @@ gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
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,
@ -502,6 +568,7 @@ gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
}
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 */

View file

@ -57,6 +57,7 @@ G_BEGIN_DECLS
typedef struct _GstVaapiPostproc GstVaapiPostproc;
typedef struct _GstVaapiPostprocClass GstVaapiPostprocClass;
typedef struct _GstVaapiDeinterlaceState GstVaapiDeinterlaceState;
/**
* GstVaapiDeinterlaceMode:
@ -70,6 +71,18 @@ typedef enum {
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.
@ -99,6 +112,26 @@ typedef enum {
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;
@ -129,6 +162,7 @@ struct _GstVaapiPostproc {
/* Deinterlacing */
GstVaapiDeinterlaceMode deinterlace_mode;
GstVaapiDeinterlaceMethod deinterlace_method;
GstVaapiDeinterlaceState deinterlace_state;
GstClockTime field_duration;
guint is_raw_yuv : 1;