);
static void gst_deinterlace2_finalize (GObject * object);
-
static void gst_deinterlace2_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_deinterlace2_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_deinterlace2_setcaps (GstPad * pad, GstCaps * caps);
-
static gboolean gst_deinterlace2_sink_event (GstPad * pad, GstEvent * event);
-
static GstFlowReturn gst_deinterlace2_chain (GstPad * pad, GstBuffer * buffer);
-
static GstStateChangeReturn gst_deinterlace2_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_deinterlace2_src_event (GstPad * pad, GstEvent * event);
-
static gboolean gst_deinterlace2_src_query (GstPad * pad, GstQuery * query);
-
static const GstQueryType *gst_deinterlace2_src_query_types (GstPad * pad);
-static void gst_deinterlace2_deinterlace_scanlines (GstDeinterlace2 * object);
-
static void gst_deinterlace2_reset (GstDeinterlace2 * object);
GST_BOILERPLATE (GstDeinterlace2, gst_deinterlace2, GstElement,
GST_DEINTERLACE2_ALL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
);
-
g_object_class_install_property (gobject_class, ARG_FIELDS,
g_param_spec_enum ("tff",
"tff",
GST_WARNING ("Invalid Deinterlacer Method");
}
-
- if (object->method->deinterlace_frame == NULL)
- object->method->deinterlace_frame = gst_deinterlace2_deinterlace_scanlines;
-
/* TODO: if current method requires less fields in the history,
pop the diff from field_history.
*/
-
}
static void
gst_deinterlace2_push_history (GstDeinterlace2 * object, GstBuffer * buffer)
{
int i = 1;
-
GstClockTime timestamp;
-
GstClockTime field_diff;
g_assert (object->history_count < MAX_FIELD_HISTORY - 2);
GST_DEBUG ("push, size(history): %d", object->history_count);
}
-/* some methods support only deinterlace_/copy_scanline functions.
- This funtion calls them in the right manner. */
-static void
-gst_deinterlace2_deinterlace_scanlines (GstDeinterlace2 * object)
-{
-
- gint line = 1;
-
- gint cur_field_idx = object->history_count - object->method->fields_required;
-
- GST_INFO ("cur_field_idx: %d", cur_field_idx);
-
- guint8 *out_data = GST_BUFFER_DATA (object->out_buf);
-
- guint8 *cur_field =
- GST_BUFFER_DATA (object->field_history[cur_field_idx].buf);
- guint8 *last_field = NULL;
-
- guint8 *second_last_field = NULL;
-
- /* method can just handle up to 3 history fields,
- bcs until now there isn't a plugin (with interp./copy scanline methods)
- that uses more */
- g_assert (object->method->fields_required <= 3);
-
- if (object->method->fields_required >= 2) {
- last_field = GST_BUFFER_DATA (object->field_history[cur_field_idx + 1].buf);
- }
- if (object->method->fields_required >= 3) {
- second_last_field =
- GST_BUFFER_DATA (object->field_history[cur_field_idx + 2].buf);
- }
-
- if (object->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM) {
- /* double the first scanline of the bottom field */
- blit_packed422_scanline (out_data, cur_field, object->frame_width);
- out_data += object->output_stride;
- }
-
- blit_packed422_scanline (out_data, cur_field, object->frame_width);
- out_data += object->output_stride;
- line++;
-
- for (; line <= object->field_height;) {
- deinterlace_scanline_data_t data;
-
- /* interp. scanline */
- data.t0 = cur_field;
- data.b0 = cur_field + object->field_stride;
-
- if (last_field != NULL) {
- data.tt1 = last_field;
- data.m1 = last_field + object->field_stride;
- data.bb1 = last_field + (object->field_stride * 2);
-
- last_field += object->field_stride;
- }
-
- if (second_last_field != NULL) {
- data.t2 = second_last_field;
- data.b2 = second_last_field + object->field_stride;
- }
-
- /* set valid data for corner cases */
- if (line == 2) {
- data.tt1 = data.bb1;
- } else if (line == object->field_height) {
- data.bb1 = data.tt1;
- }
-
- object->method->interpolate_scanline (object, &data, out_data);
- out_data += object->output_stride;
-
- /* copy a scanline */
- data.tt0 = cur_field;
- data.m0 = cur_field + (object->field_stride);
- data.bb0 = cur_field + (object->field_stride * 2);
- cur_field += object->field_stride;
-
- if (last_field != NULL) {
- data.t1 = last_field;
- data.b1 = last_field + object->field_stride;
- }
-
- if (second_last_field != NULL) {
- data.tt2 = second_last_field;
- data.m2 = second_last_field + (object->field_stride);
- data.bb2 = second_last_field + (object->field_stride * 2);
- second_last_field += object->field_stride;
- }
-
- /* set valid data for corner cases */
- if (line == object->field_height) {
- data.bb0 = data.tt0;
- data.bb2 = data.tt2;
- data.b1 = data.t1;
- }
-
- object->method->copy_scanline (object, &data, out_data);
- out_data += object->output_stride;
- line++;
- }
-
- if (object->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP) {
- /* double the last scanline of the top field */
- blit_packed422_scanline (out_data, cur_field, object->frame_width);
- }
-}
-
static GstFlowReturn
gst_deinterlace2_chain (GstPad * pad, GstBuffer * buf)
{
GstDeinterlace2 *object = NULL;
-
GstClockTime timestamp;
-
GstFlowReturn ret = GST_FLOW_OK;
object = GST_DEINTERLACE2 (GST_PAD_PARENT (pad));
othercaps = gst_caps_ref (caps);
}
- if ( /*!gst_pad_accept_caps (otherpad, othercaps)
- || */ !gst_pad_set_caps (otherpad, othercaps))
+ if (!gst_pad_set_caps (otherpad, othercaps))
goto caps_not_accepted;
gst_caps_unref (othercaps);
gst_deinterlace2_sink_event (GstPad * pad, GstEvent * event)
{
gboolean res = TRUE;
-
GstDeinterlace2 *object = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
GST_LOG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
gst_deinterlace2_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret;
-
GstDeinterlace2 *object = GST_DEINTERLACE2 (element);
switch (transition) {
gst_deinterlace2_src_event (GstPad * pad, GstEvent * event)
{
GstDeinterlace2 *object = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
-
gboolean res;
GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
gst_deinterlace2_src_query (GstPad * pad, GstQuery * query)
{
GstDeinterlace2 *object = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
-
gboolean res = FALSE;
GST_LOG_OBJECT (object, "%s query", GST_QUERY_TYPE_NAME (query));
case GST_QUERY_LATENCY:
{
GstClockTime min, max;
-
gboolean live;
-
GstPad *peer;
if ((peer = gst_pad_get_peer (object->sinkpad))) {
// I'd intended this to be part of a larger more elaborate method added to
// Blended Clip but this give too good results for the CPU to ignore here.
-static void
-copy_scanline (GstDeinterlace2 * object,
- deinterlace_scanline_data_t * data, uint8_t * output)
-{
- blit_packed422_scanline (output, data->m1, object->frame_width);
-}
-
static const int GreedyMaxComb = 15;
static inline void
-deinterlace_greedy_packed422_scanline_c (GstDeinterlace2 * object,
- uint8_t * m0, uint8_t * t1, uint8_t * b1, uint8_t * m2, uint8_t * output,
- int width)
+deinterlace_greedy_packed422_scanline_c (uint8_t * m0, uint8_t * t1,
+ uint8_t * b1, uint8_t * m2, uint8_t * output, int width)
{
int avg, l2_diff, lp2_diff, max, min, best;
#ifdef HAVE_CPU_I386
#include "mmx.h"
static void
-deinterlace_greedy_packed422_scanline_mmx (GstDeinterlace2 * object,
- uint8_t * m0, uint8_t * t1, uint8_t * b1, uint8_t * m2, uint8_t * output,
- int width)
+deinterlace_greedy_packed422_scanline_mmx (uint8_t * m0, uint8_t * t1,
+ uint8_t * b1, uint8_t * m2, uint8_t * output, int width)
{
mmx_t MaxComb;
}
emms ();
if (width > 0)
- deinterlace_greedy_packed422_scanline_c (object, m0, t1, b1, m2, output,
- width);
+ deinterlace_greedy_packed422_scanline_c (m0, t1, b1, m2, output, width);
}
#include "sse.h"
static void
-deinterlace_greedy_packed422_scanline_mmxext (GstDeinterlace2 * object,
- uint8_t * m0, uint8_t * t1, uint8_t * b1, uint8_t * m2, uint8_t * output,
- int width)
+deinterlace_greedy_packed422_scanline_mmxext (uint8_t * m0, uint8_t * t1,
+ uint8_t * b1, uint8_t * m2, uint8_t * output, int width)
{
mmx_t MaxComb;
emms ();
if (width > 0)
- deinterlace_greedy_packed422_scanline_c (object, m0, t1, b1, m2, output,
- width);
+ deinterlace_greedy_packed422_scanline_c (m0, t1, b1, m2, output, width);
}
#endif
static void
-deinterlace_greedy_packed422_scanline (GstDeinterlace2 * object,
- deinterlace_scanline_data_t * data, uint8_t * output)
+deinterlace_frame_di_greedy (GstDeinterlace2 * object)
{
+ void (*func) (uint8_t * L2, uint8_t * L1, uint8_t * L3, uint8_t * L2P,
+ uint8_t * Dest, int size);
+
+ int InfoIsOdd = 0;
+ int Line;
+ unsigned int Pitch = object->field_stride;
+ unsigned char *L1; // ptr to Line1, of 3
+ unsigned char *L2; // ptr to Line2, the weave line
+ unsigned char *L3; // ptr to Line3
+
+ unsigned char *L2P; // ptr to prev Line2
+ unsigned char *Dest = GST_BUFFER_DATA (object->out_buf);
+
#ifdef HAVE_CPU_I386
if (object->cpu_feature_flags & OIL_IMPL_FLAG_MMXEXT) {
- deinterlace_greedy_packed422_scanline_mmxext (object, data->m0, data->t1,
- data->b1, data->m2, output, 2 * object->frame_width);
+ func = deinterlace_greedy_packed422_scanline_mmxext;
} else if (object->cpu_feature_flags & OIL_IMPL_FLAG_MMX) {
- deinterlace_greedy_packed422_scanline_mmx (object, data->m0, data->t1,
- data->b1, data->m2, output, 2 * object->frame_width);
+ func = deinterlace_greedy_packed422_scanline_mmx;
} else {
- deinterlace_greedy_packed422_scanline_c (object, data->m0, data->t1,
- data->b1, data->m2, output, 2 * object->frame_width);
+ func = deinterlace_greedy_packed422_scanline_c;
}
#else
- deinterlace_greedy_packed422_scanline_c (object, data->m0, data->t1, data->b1,
- data->m2, output, 2 * object->frame_width);
+ func = deinterlace_greedy_packed422_scanline_c;
#endif
-}
+ // copy first even line no matter what, and the first odd line if we're
+ // processing an EVEN field. (note diff from other deint rtns.)
+
+ if (object->field_history[object->history_count - 1].flags ==
+ PICTURE_INTERLACED_BOTTOM) {
+ InfoIsOdd = 1;
+
+ L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf);
+ L2 = GST_BUFFER_DATA (object->field_history[object->history_count - 1].buf);
+ L3 = L1 + Pitch;
+ L2P =
+ GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf);
+
+ // copy first even line
+ object->pMemcpy (Dest, L1, object->line_length);
+ Dest += object->output_stride;
+ } else {
+ InfoIsOdd = 0;
+ L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf);
+ L2 = GST_BUFFER_DATA (object->field_history[object->history_count -
+ 1].buf) + Pitch;
+ L3 = L1 + Pitch;
+ L2P =
+ GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf) +
+ Pitch;
+
+ // copy first even line
+ object->pMemcpy (Dest, GST_BUFFER_DATA (object->field_history[0].buf),
+ object->line_length);
+ Dest += object->output_stride;
+ // then first odd line
+ object->pMemcpy (Dest, L1, object->line_length);
+ Dest += object->output_stride;
+ }
+
+ for (Line = 0; Line < (object->field_height - 1); ++Line) {
+ func (L2, L1, L3, L2P, Dest, object->line_length);
+ Dest += object->output_stride;
+ object->pMemcpy (Dest, L3, object->line_length);
+ Dest += object->output_stride;
+
+ L1 += Pitch;
+ L2 += Pitch;
+ L3 += Pitch;
+ L2P += Pitch;
+ }
+
+ if (InfoIsOdd) {
+ object->pMemcpy (Dest, L2, object->line_length);
+ }
+}
static deinterlace_method_t greedyl_method = {
0, //DEINTERLACE_PLUGIN_API_VERSION,
"Motion Adaptive: Simple Detection",
"AdaptiveSimple",
- 3,
+ 4,
0,
0,
0,
0,
1,
- copy_scanline,
- deinterlace_greedy_packed422_scanline,
0,
+ 0,
+ deinterlace_frame_di_greedy,
{"Uses heuristics to detect motion in the input",
"frames and reconstruct image detail where",
"possible. Use this for high quality output",
avg_l = (l1_l + l3_l) / 2;
avg_c = (l1_c + l3_c) / 2;
+ if (Pos == 0) {
+ avg_l__1 = avg_l;
+ avg_c__1 = avg_c;
+ }
+
/* Average of next L1 and next L3 */
avg_l_1 = (l1_1_l + l3_1_l) / 2;
avg_c_1 = (l1_1_c + l3_1_c) / 2;
}
#endif
-/*
- * The commented-out method below that uses the bottom_field member is more
- * like the filter as specified in the MPEG2 spec, but it doesn't seem to
- * have the desired effect.
- */
-
static void
-deinterlace_scanline_vfir (GstDeinterlace2 * object,
- deinterlace_scanline_data_t * data, uint8_t * output)
+deinterlace_frame_vfir (GstDeinterlace2 * object)
{
+ void (*func) (uint8_t * dst, uint8_t * lum_m4,
+ uint8_t * lum_m3, uint8_t * lum_m2,
+ uint8_t * lum_m1, uint8_t * lum, int size);
+ gint line = 0;
+ uint8_t *cur_field, *last_field;
+ uint8_t *t0, *b0, *tt1, *m1, *bb1, *out_data;
+
#ifdef HAVE_CPU_I386
if (object->cpu_feature_flags & OIL_IMPL_FLAG_MMX) {
- deinterlace_line_mmx (output, data->tt1, data->t0, data->m1, data->b0,
- data->bb1, object->frame_width * 2);
+ func = deinterlace_line_mmx;
} else {
- deinterlace_line_c (output, data->tt1, data->t0, data->m1, data->b0,
- data->bb1, object->frame_width * 2);
+ func = deinterlace_line_c;
}
#else
- deinterlace_line_c (output, data->tt1, data->t0, data->m1, data->b0,
- data->bb1, object->frame_width * 2);
+ func = deinterlace_line_c;
#endif
- // blit_packed422_scanline( output, data->m1, width );
-}
-static void
-copy_scanline (GstDeinterlace2 * object,
- deinterlace_scanline_data_t * data, uint8_t * output)
-{
- blit_packed422_scanline (output, data->m0, object->frame_width);
- /*
- if( data->bottom_field ) {
- deinterlace_line( output, data->tt2, data->t1, data->m2, data->b1, data->bb2, width*2 );
- } else {
- deinterlace_line( output, data->tt0, data->t1, data->m0, data->b1, data->bb0, width*2 );
- }
- */
-}
+ cur_field =
+ GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf);
+ last_field =
+ GST_BUFFER_DATA (object->field_history[object->history_count - 1].buf);
+
+ out_data = GST_BUFFER_DATA (object->out_buf);
+
+ if (object->field_history[object->history_count - 2].flags ==
+ PICTURE_INTERLACED_BOTTOM) {
+ blit_packed422_scanline (out_data, cur_field, object->frame_width);
+ out_data += object->output_stride;
+ }
+ blit_packed422_scanline (out_data, cur_field, object->frame_width);
+ out_data += object->output_stride;
+ line++;
+
+ for (; line < object->field_height; line++) {
+ t0 = cur_field;
+ b0 = cur_field + object->field_stride;
+
+ tt1 = last_field;
+ m1 = last_field + object->field_stride;
+ bb1 = last_field + (object->field_stride * 2);
+
+ /* set valid data for corner cases */
+ if (line == 1) {
+ tt1 = bb1;
+ } else if (line == object->field_height - 1) {
+ bb1 = tt1;
+ }
+
+ func (out_data, tt1, t0, m1, b0, bb1, object->line_length);
+ out_data += object->output_stride;
+ cur_field += object->field_stride;
+ last_field += object->field_stride;
+
+ blit_packed422_scanline (out_data, cur_field, object->frame_width);
+ out_data += object->output_stride;
+ }
+
+ if (object->field_history[object->history_count - 2].flags ==
+ PICTURE_INTERLACED_TOP) {
+ /* double the last scanline of the top field */
+ blit_packed422_scanline (out_data, cur_field, object->frame_width);
+ }
+}
static deinterlace_method_t vfirmethod = {
0, //DEINTERLACE_PLUGIN_API_VERSION,
0,
0,
1,
- deinterlace_scanline_vfir,
- copy_scanline,
0,
+ 0,
+ deinterlace_frame_vfir,
{"Avoids flicker by blurring consecutive frames",
"of input. Use this if you want to run your",
"monitor at an arbitrary refresh rate and not",