mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 09:40:37 +00:00
deinterlace: Implement field history flushing
In a number of cases it is necessary to flush the field history by performing 'degraded' deinterlacing - that is, using the user-chosen method for as many fields as possible, then using vfir for as long as there are >= 2 fields remaining in the history, then using linear for the last field. This should avoid losing fields being kept for history for example at EOS. This may address part of #633294
This commit is contained in:
parent
5a56274cba
commit
9be159b32c
2 changed files with 74 additions and 42 deletions
|
@ -66,12 +66,6 @@ enum
|
|||
PROP_LAST
|
||||
};
|
||||
|
||||
#define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
|
||||
static GType
|
||||
gst_deinterlace_methods_get_type (void)
|
||||
{
|
||||
static GType deinterlace_methods_type = 0;
|
||||
|
||||
static const GEnumValue methods_types[] = {
|
||||
{GST_DEINTERLACE_TOMSMOCOMP, "Motion Adaptive: Motion Search",
|
||||
"tomsmocomp"},
|
||||
|
@ -91,6 +85,13 @@ gst_deinterlace_methods_get_type (void)
|
|||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
|
||||
#define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
|
||||
static GType
|
||||
gst_deinterlace_methods_get_type (void)
|
||||
{
|
||||
static GType deinterlace_methods_type = 0;
|
||||
|
||||
if (!deinterlace_methods_type) {
|
||||
deinterlace_methods_type =
|
||||
g_enum_register_static ("GstDeinterlaceMethods", methods_types);
|
||||
|
@ -209,6 +210,8 @@ static gboolean gst_deinterlace_src_event (GstPad * pad, GstEvent * event);
|
|||
static gboolean gst_deinterlace_src_query (GstPad * pad, GstQuery * query);
|
||||
static const GstQueryType *gst_deinterlace_src_query_types (GstPad * pad);
|
||||
|
||||
static GstFlowReturn gst_deinterlace_output_frame (GstDeinterlace * self,
|
||||
gboolean flushing);
|
||||
static void gst_deinterlace_reset (GstDeinterlace * self);
|
||||
static void gst_deinterlace_update_qos (GstDeinterlace * self,
|
||||
gdouble proportion, GstClockTimeDiff diff, GstClockTime time);
|
||||
|
@ -575,7 +578,8 @@ gst_deinterlace_init (GstDeinterlace * self, GstDeinterlaceClass * klass)
|
|||
gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
|
||||
|
||||
self->mode = DEFAULT_MODE;
|
||||
gst_deinterlace_set_method (self, DEFAULT_METHOD);
|
||||
self->user_set_method_id = DEFAULT_METHOD;
|
||||
gst_deinterlace_set_method (self, self->user_set_method_id);
|
||||
self->fields = DEFAULT_FIELDS;
|
||||
self->field_layout = DEFAULT_FIELD_LAYOUT;
|
||||
|
||||
|
@ -585,11 +589,13 @@ gst_deinterlace_init (GstDeinterlace * self, GstDeinterlaceClass * klass)
|
|||
}
|
||||
|
||||
static void
|
||||
gst_deinterlace_reset_history (GstDeinterlace * self)
|
||||
gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all)
|
||||
{
|
||||
gint i;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Resetting history");
|
||||
if (drop_all) {
|
||||
GST_DEBUG_OBJECT (self, "Resetting history (count %d)",
|
||||
self->history_count);
|
||||
|
||||
for (i = 0; i < self->history_count; i++) {
|
||||
if (self->field_history[i].buf) {
|
||||
|
@ -597,14 +603,20 @@ gst_deinterlace_reset_history (GstDeinterlace * self)
|
|||
self->field_history[i].buf = NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (self, "Flushing history (count %d)", self->history_count);
|
||||
while (self->history_count > 0)
|
||||
gst_deinterlace_output_frame (self, TRUE);
|
||||
}
|
||||
memset (self->field_history, 0,
|
||||
GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
|
||||
self->history_count = 0;
|
||||
|
||||
if (self->last_buffer)
|
||||
if (!self->still_frame_mode && self->last_buffer) {
|
||||
gst_buffer_unref (self->last_buffer);
|
||||
self->last_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_deinterlace_update_passthrough (GstDeinterlace * self)
|
||||
|
@ -648,7 +660,7 @@ gst_deinterlace_reset (GstDeinterlace * self)
|
|||
gst_caps_unref (self->request_caps);
|
||||
self->request_caps = NULL;
|
||||
|
||||
gst_deinterlace_reset_history (self);
|
||||
gst_deinterlace_reset_history (self, TRUE);
|
||||
|
||||
gst_deinterlace_reset_qos (self);
|
||||
}
|
||||
|
@ -679,7 +691,8 @@ gst_deinterlace_set_property (GObject * object, guint prop_id,
|
|||
break;
|
||||
}
|
||||
case PROP_METHOD:
|
||||
gst_deinterlace_set_method (self, g_value_get_enum (value));
|
||||
self->user_set_method_id = g_value_get_enum (value);
|
||||
gst_deinterlace_set_method (self, self->user_set_method_id);
|
||||
break;
|
||||
case PROP_FIELDS:{
|
||||
gint new_fields;
|
||||
|
@ -718,7 +731,7 @@ gst_deinterlace_get_property (GObject * object, guint prop_id,
|
|||
g_value_set_enum (value, self->mode);
|
||||
break;
|
||||
case PROP_METHOD:
|
||||
g_value_set_enum (value, self->method_id);
|
||||
g_value_set_enum (value, self->user_set_method_id);
|
||||
break;
|
||||
case PROP_FIELDS:
|
||||
g_value_set_enum (value, self->fields);
|
||||
|
@ -941,7 +954,7 @@ gst_deinterlace_do_qos (GstDeinterlace * self, GstClockTime timestamp)
|
|||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_deinterlace_output_frame (GstDeinterlace * self)
|
||||
gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
|
||||
{
|
||||
GstClockTime timestamp;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
@ -949,14 +962,29 @@ gst_deinterlace_output_frame (GstDeinterlace * self)
|
|||
gint cur_field_idx = 0;
|
||||
GstBuffer *buf, *outbuf;
|
||||
|
||||
gst_deinterlace_set_method (self, self->user_set_method_id);
|
||||
fields_required = gst_deinterlace_method_get_fields_required (self->method);
|
||||
|
||||
/* Not enough fields in the history */
|
||||
if (self->history_count < fields_required) {
|
||||
if (flushing) {
|
||||
/* FIXME: if there are any methods implemented that output different
|
||||
* dimensions (e.g. half height) that require more than one field of
|
||||
* history, it is desirable to degrade to something that outputs
|
||||
* half-height also */
|
||||
gst_deinterlace_set_method (self,
|
||||
self->history_count >= 2 ?
|
||||
GST_DEINTERLACE_VFIR : GST_DEINTERLACE_LINEAR);
|
||||
fields_required =
|
||||
gst_deinterlace_method_get_fields_required (self->method);
|
||||
GST_DEBUG_OBJECT (self, "Flushing field(s) using %s method",
|
||||
methods_types[self->method_id].value_nick);
|
||||
} else {
|
||||
/* Not enough fields in the history */
|
||||
GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
|
||||
self->history_count, fields_required);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
}
|
||||
|
||||
while (self->history_count >= fields_required) {
|
||||
if (self->fields == GST_DEINTERLACE_ALL)
|
||||
|
@ -1149,13 +1177,13 @@ gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
|
|||
|
||||
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
|
||||
GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
|
||||
gst_deinterlace_reset_history (self);
|
||||
gst_deinterlace_reset_history (self, FALSE);
|
||||
}
|
||||
|
||||
gst_deinterlace_push_history (self, buf);
|
||||
buf = NULL;
|
||||
|
||||
return gst_deinterlace_output_frame (self);
|
||||
return gst_deinterlace_output_frame (self, FALSE);
|
||||
}
|
||||
|
||||
static gint
|
||||
|
@ -1396,6 +1424,8 @@ gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
|
|||
gst_caps_set_simple (othercaps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||
}
|
||||
|
||||
gst_deinterlace_reset_history (self, FALSE);
|
||||
|
||||
if (!gst_pad_set_caps (otherpad, othercaps))
|
||||
goto caps_not_accepted;
|
||||
|
||||
|
@ -1473,7 +1503,7 @@ gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
|
|||
}
|
||||
|
||||
gst_deinterlace_reset_qos (self);
|
||||
gst_deinterlace_reset_history (self);
|
||||
gst_deinterlace_reset_history (self, FALSE);
|
||||
res = gst_pad_push_event (self->srcpad, event);
|
||||
break;
|
||||
}
|
||||
|
@ -1489,6 +1519,7 @@ gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
|
|||
|
||||
GST_DEBUG_OBJECT (self, "Handling still frame");
|
||||
self->still_frame_mode = TRUE;
|
||||
gst_deinterlace_reset_history (self, FALSE);
|
||||
if (self->last_buffer) {
|
||||
ret =
|
||||
gst_pad_push (self->srcpad, gst_buffer_ref (self->last_buffer));
|
||||
|
@ -1505,7 +1536,7 @@ gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
|
|||
}
|
||||
/* fall through */
|
||||
case GST_EVENT_EOS:
|
||||
gst_deinterlace_reset_history (self);
|
||||
gst_deinterlace_reset_history (self, FALSE);
|
||||
|
||||
/* fall through */
|
||||
default:
|
||||
|
@ -1519,7 +1550,7 @@ gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
|
|||
}
|
||||
gst_deinterlace_reset_qos (self);
|
||||
res = gst_pad_push_event (self->srcpad, event);
|
||||
gst_deinterlace_reset_history (self);
|
||||
gst_deinterlace_reset_history (self, TRUE);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,8 @@ struct _GstDeinterlace
|
|||
|
||||
GstDeinterlaceFields fields;
|
||||
|
||||
GstDeinterlaceMethods method_id;
|
||||
GstDeinterlaceMethods method_id; /* current state (differs when flushing) */
|
||||
GstDeinterlaceMethods user_set_method_id; /* property value */
|
||||
GstDeinterlaceMethod *method;
|
||||
|
||||
GstVideoFormat format;
|
||||
|
|
Loading…
Reference in a new issue