gstdeinterlace.c 51 KB
Newer Older
1
2
3
/*
 * GStreamer
 * Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
4
 * Copyright (C) 2008-2010 Sebastian Dröge <slomo@collabora.co.uk>
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

22
/**
23
 * SECTION:element-deinterlace
24
 *
25
 * deinterlace deinterlaces interlaced video frames to progressive video frames.
26
27
28
29
30
 * For this different algorithms can be selected which will be described later.
 *
 * <refsect2>
 * <title>Example launch line</title>
 * |[
31
 * gst-launch -v filesrc location=/path/to/file ! decodebin2 ! ffmpegcolorspace ! deinterlace ! ffmpegcolorspace ! autovideosink
32
33
34
35
 * ]| This pipeline deinterlaces a video file with the default deinterlacing options.
 * </refsect2>
 */

36
37
38
39
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

40
#include "gstdeinterlace.h"
41
42
#include "tvtime/plugins.h"

43
44
#include <string.h>

45
46
GST_DEBUG_CATEGORY_STATIC (deinterlace_debug);
#define GST_CAT_DEFAULT (deinterlace_debug)
47

48
49
/* Properties */

50
#define DEFAULT_MODE            GST_DEINTERLACE_MODE_AUTO
51
52
53
#define DEFAULT_METHOD          GST_DEINTERLACE_GREEDY_H
#define DEFAULT_FIELDS          GST_DEINTERLACE_ALL
#define DEFAULT_FIELD_LAYOUT    GST_DEINTERLACE_LAYOUT_AUTO
54

55
56
enum
{
57
  PROP_0,
58
  PROP_MODE,
59
60
61
62
  PROP_METHOD,
  PROP_FIELDS,
  PROP_FIELD_LAYOUT,
  PROP_LAST
63
64
};

65
#define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
66
static GType
67
gst_deinterlace_methods_get_type (void)
68
{
69
  static GType deinterlace_methods_type = 0;
70

71
  static const GEnumValue methods_types[] = {
72
    {GST_DEINTERLACE_TOMSMOCOMP, "Motion Adaptive: Motion Search",
73
        "tomsmocomp"},
74
    {GST_DEINTERLACE_GREEDY_H, "Motion Adaptive: Advanced Detection",
75
        "greedyh"},
76
77
78
79
80
81
82
83
    {GST_DEINTERLACE_GREEDY_L, "Motion Adaptive: Simple Detection", "greedyl"},
    {GST_DEINTERLACE_VFIR, "Blur Vertical", "vfir"},
    {GST_DEINTERLACE_LINEAR, "Television: Full resolution", "linear"},
    {GST_DEINTERLACE_LINEAR_BLEND, "Blur: Temporal", "linearblend"},
    {GST_DEINTERLACE_SCALER_BOB, "Double lines", "scalerbob"},
    {GST_DEINTERLACE_WEAVE, "Weave", "weave"},
    {GST_DEINTERLACE_WEAVE_TFF, "Progressive: Top Field First", "weavetff"},
    {GST_DEINTERLACE_WEAVE_BFF, "Progressive: Bottom Field First", "weavebff"},
84
85
86
    {0, NULL, NULL},
  };

87
88
89
  if (!deinterlace_methods_type) {
    deinterlace_methods_type =
        g_enum_register_static ("GstDeinterlaceMethods", methods_types);
90
  }
91
  return deinterlace_methods_type;
92
93
}

94
#define GST_TYPE_DEINTERLACE_FIELDS (gst_deinterlace_fields_get_type ())
95
static GType
96
gst_deinterlace_fields_get_type (void)
97
{
98
  static GType deinterlace_fields_type = 0;
99
100

  static const GEnumValue fields_types[] = {
101
102
103
    {GST_DEINTERLACE_ALL, "All fields", "all"},
    {GST_DEINTERLACE_TF, "Top fields only", "top"},
    {GST_DEINTERLACE_BF, "Bottom fields only", "bottom"},
104
105
106
    {0, NULL, NULL},
  };

107
108
109
  if (!deinterlace_fields_type) {
    deinterlace_fields_type =
        g_enum_register_static ("GstDeinterlaceFields", fields_types);
110
  }
111
  return deinterlace_fields_type;
112
113
}

114
#define GST_TYPE_DEINTERLACE_FIELD_LAYOUT (gst_deinterlace_field_layout_get_type ())
115
static GType
116
gst_deinterlace_field_layout_get_type (void)
117
{
118
  static GType deinterlace_field_layout_type = 0;
119
120

  static const GEnumValue field_layout_types[] = {
121
122
123
    {GST_DEINTERLACE_LAYOUT_AUTO, "Auto detection", "auto"},
    {GST_DEINTERLACE_LAYOUT_TFF, "Top field first", "tff"},
    {GST_DEINTERLACE_LAYOUT_BFF, "Bottom field first", "bff"},
124
125
126
    {0, NULL, NULL},
  };

127
128
129
  if (!deinterlace_field_layout_type) {
    deinterlace_field_layout_type =
        g_enum_register_static ("GstDeinterlaceFieldLayout",
130
131
        field_layout_types);
  }
132
  return deinterlace_field_layout_type;
133
134
}

135
#define GST_TYPE_DEINTERLACE_MODES (gst_deinterlace_modes_get_type ())
136
static GType
137
gst_deinterlace_modes_get_type (void)
138
{
139
  static GType deinterlace_modes_type = 0;
140
141

  static const GEnumValue modes_types[] = {
142
    {GST_DEINTERLACE_MODE_AUTO, "Auto detection", "auto"},
143
    {GST_DEINTERLACE_MODE_INTERLACED, "Force deinterlacing", "interlaced"},
144
    {GST_DEINTERLACE_MODE_DISABLED, "Run in passthrough mode", "disabled"},
145
146
147
    {0, NULL, NULL},
  };

148
149
150
  if (!deinterlace_modes_type) {
    deinterlace_modes_type =
        g_enum_register_static ("GstDeinterlaceModes", modes_types);
151
  }
152
  return deinterlace_modes_type;
153
154
}

155
156
157
static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
158
159
160
161
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y444") ";"
        GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("YVYU") ";"
        GST_VIDEO_CAPS_YUV ("Y42B") ";" GST_VIDEO_CAPS_YUV ("I420") ";"
        GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("Y41B"))
162
163
164
165
166
    );

static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
167
168
169
170
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y444") ";"
        GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("YVYU") ";"
        GST_VIDEO_CAPS_YUV ("Y42B") ";" GST_VIDEO_CAPS_YUV ("I420") ";"
        GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("Y41B"))
171
172
    );

173
174
static void gst_deinterlace_finalize (GObject * self);
static void gst_deinterlace_set_property (GObject * self, guint prop_id,
175
    const GValue * value, GParamSpec * pspec);
176
static void gst_deinterlace_get_property (GObject * self, guint prop_id,
177
178
    GValue * value, GParamSpec * pspec);

179
180
181
static GstCaps *gst_deinterlace_getcaps (GstPad * pad);
static gboolean gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps);
static gboolean gst_deinterlace_sink_event (GstPad * pad, GstEvent * event);
182
static gboolean gst_deinterlace_sink_query (GstPad * pad, GstQuery * query);
183
static GstFlowReturn gst_deinterlace_chain (GstPad * pad, GstBuffer * buffer);
184
185
static GstFlowReturn gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset,
    guint size, GstCaps * caps, GstBuffer ** buf);
186
static GstStateChangeReturn gst_deinterlace_change_state (GstElement * element,
187
188
    GstStateChange transition);

189
190
191
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);
192

193
static void gst_deinterlace_reset (GstDeinterlace * self);
194
static void gst_deinterlace_update_qos (GstDeinterlace * self,
195
    gdouble proportion, GstClockTimeDiff diff, GstClockTime time);
196
197
198
static void gst_deinterlace_reset_qos (GstDeinterlace * self);
static void gst_deinterlace_read_qos (GstDeinterlace * self,
    gdouble * proportion, GstClockTime * time);
199

200
static void gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
201
202
203
204
205
206
    gpointer iface_data);

static void
_do_init (GType object_type)
{
  const GInterfaceInfo child_proxy_interface_info = {
207
    (GInterfaceInitFunc) gst_deinterlace_child_proxy_interface_init,
208
209
210
211
212
213
214
215
    NULL,                       /* interface_finalize */
    NULL                        /* interface_data */
  };

  g_type_add_interface_static (object_type, GST_TYPE_CHILD_PROXY,
      &child_proxy_interface_info);
}

216
GST_BOILERPLATE_FULL (GstDeinterlace, gst_deinterlace, GstElement,
217
218
    GST_TYPE_ELEMENT, _do_init);

219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
static const struct
{
  GType (*get_type) (void);
} _method_types[] = {
  {
  gst_deinterlace_method_tomsmocomp_get_type}, {
  gst_deinterlace_method_greedy_h_get_type}, {
  gst_deinterlace_method_greedy_l_get_type}, {
  gst_deinterlace_method_vfir_get_type}, {
  gst_deinterlace_method_linear_get_type}, {
  gst_deinterlace_method_linear_blend_get_type}, {
  gst_deinterlace_method_scaler_bob_get_type}, {
  gst_deinterlace_method_weave_get_type}, {
  gst_deinterlace_method_weave_tff_get_type}, {
  gst_deinterlace_method_weave_bff_get_type}
};

236
static void
237
gst_deinterlace_set_method (GstDeinterlace * self, GstDeinterlaceMethods method)
238
{
239
240
  GType method_type;

241
  GST_DEBUG_OBJECT (self, "Setting new method %d", method);
242

243
  if (self->method) {
244
245
246
247
248
249
250
    if (self->method_id == method &&
        gst_deinterlace_method_supported (G_TYPE_FROM_INSTANCE (self->method),
            self->format, self->width, self->height)) {
      GST_DEBUG_OBJECT (self, "Reusing current method");
      return;
    }

251
252
253
254
    gst_child_proxy_child_removed (GST_OBJECT (self),
        GST_OBJECT (self->method));
    gst_object_unparent (GST_OBJECT (self->method));
    self->method = NULL;
255
256
  }

257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  method_type =
      _method_types[method].get_type !=
      NULL ? _method_types[method].get_type () : G_TYPE_INVALID;
  if (method_type == G_TYPE_INVALID
      || !gst_deinterlace_method_supported (method_type, self->format,
          self->width, self->height)) {
    GType tmp;
    gint i;

    method_type = G_TYPE_INVALID;

    GST_WARNING_OBJECT (self, "Method doesn't support requested format");
    for (i = 0; i < G_N_ELEMENTS (_method_types); i++) {
      if (_method_types[i].get_type == NULL)
        continue;
      tmp = _method_types[i].get_type ();
      if (gst_deinterlace_method_supported (tmp, self->format, self->width,
              self->height)) {
        GST_DEBUG_OBJECT (self, "Using method %d", i);
        method_type = tmp;
        break;
      }
    }
    /* If we get here we must have invalid caps! */
    g_assert (method_type != G_TYPE_INVALID);
282
283
  }

284
  self->method = g_object_new (method_type, NULL);
285
  self->method_id = method;
286

287
288
289
  gst_object_set_name (GST_OBJECT (self->method), "method");
  gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
  gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
290
291
292
293

  if (self->method)
    gst_deinterlace_method_setup (self->method, self->format, self->width,
        self->height);
294
}
295

296
297
298
299
300
301
302
static gboolean
gst_deinterlace_clip_buffer (GstDeinterlace * self, GstBuffer * buffer)
{
  gboolean ret = TRUE;
  GstClockTime start, stop;
  gint64 cstart, cstop;

303
304
305
306
307
308
309
  GST_DEBUG_OBJECT (self,
      "Clipping buffer to the current segment: %" GST_TIME_FORMAT " -- %"
      GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
      GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
  GST_DEBUG_OBJECT (self, "Current segment: %" GST_SEGMENT_FORMAT,
      &self->segment);

310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  if (G_UNLIKELY (self->segment.format != GST_FORMAT_TIME))
    goto beach;
  if (G_UNLIKELY (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)))
    goto beach;

  start = GST_BUFFER_TIMESTAMP (buffer);
  stop = start + GST_BUFFER_DURATION (buffer);

  if (!(ret = gst_segment_clip (&self->segment, GST_FORMAT_TIME,
              start, stop, &cstart, &cstop)))
    goto beach;

  GST_BUFFER_TIMESTAMP (buffer) = cstart;
  if (GST_CLOCK_TIME_IS_VALID (cstop))
    GST_BUFFER_DURATION (buffer) = cstop - cstart;

beach:
327
328
329
330
331
332
333
334
  if (ret)
    GST_DEBUG_OBJECT (self,
        "Clipped buffer to the current segment: %" GST_TIME_FORMAT " -- %"
        GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
        GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
  else
    GST_DEBUG_OBJECT (self, "Buffer outside the current segment -- dropping");

335
336
337
  return ret;
}

338
static void
339
gst_deinterlace_base_init (gpointer klass)
340
341
342
343
344
345
346
347
348
349
350
351
352
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);

  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&src_templ));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&sink_templ));

  gst_element_class_set_details_simple (element_class,
      "Deinterlacer",
      "Filter/Video",
      "Deinterlace Methods ported from DScaler/TvTime",
      "Martin Eikermann <meiker@upb.de>, "
353
      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
354
355
356
}

static void
357
gst_deinterlace_class_init (GstDeinterlaceClass * klass)
358
359
360
361
362
{
  GObjectClass *gobject_class = (GObjectClass *) klass;

  GstElementClass *element_class = (GstElementClass *) klass;

363
364
365
  gobject_class->set_property = gst_deinterlace_set_property;
  gobject_class->get_property = gst_deinterlace_get_property;
  gobject_class->finalize = gst_deinterlace_finalize;
366

367
  /**
368
   * GstDeinterlace:mode
369
370
371
372
373
374
   * 
   * This selects whether the deinterlacing methods should
   * always be applied or if they should only be applied
   * on content that has the "interlaced" flag on the caps.
   *
   */
375
376
377
378
  g_object_class_install_property (gobject_class, PROP_MODE,
      g_param_spec_enum ("mode",
          "Mode",
          "Deinterlace Mode",
379
          GST_TYPE_DEINTERLACE_MODES,
380
381
382
          DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
      );

383
  /**
384
   * GstDeinterlace:method
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
   * 
   * Selects the different deinterlacing algorithms that can be used.
   * These provide different quality and CPU usage.
   *
   * Some methods provide parameters which can be set by getting
   * the "method" child via the #GstChildProxy interface and
   * setting the appropiate properties on it.
   *
   * <itemizedlist>
   * <listitem>
   * <para>
   * tomsmocomp
   * Motion Adaptive: Motion Search
   * </para>
   * </listitem>
   * <listitem>
   * <para>
   * greedyh
   * Motion Adaptive: Advanced Detection
   * </para>
   * </listitem>
   * <listitem>
   * <para>
   * greedyl
   * Motion Adaptive: Simple Detection
   * </para>
   * </listitem>
   * <listitem>
   * <para>
   * vfir
   * Blur vertical
   * </para>
   * </listitem>
   * <listitem>
   * <para>
   * linear
   * Linear interpolation
   * </para>
   * </listitem>
   * <listitem>
   * <para>
   * linearblend
   * Linear interpolation in time domain
   * </para>
   * </listitem>
   * <listitem>
   * <para>
   * scalerbob
   * Double lines
   * </para>
   * </listitem>
   * <listitem>
   * <para>
   * weave
   * Weave
   * </para>
   * </listitem>
   * <listitem>
   * <para>
   * weavetff
   * Progressive: Top Field First
   * </para>
   * </listitem>
   * <listitem>
   * <para>
   * weavebff
   * Progressive: Bottom Field First
   * </para>
   * </listitem>
   * </itemizedlist>
   */
456
  g_object_class_install_property (gobject_class, PROP_METHOD,
457
458
459
      g_param_spec_enum ("method",
          "Method",
          "Deinterlace Method",
460
          GST_TYPE_DEINTERLACE_METHODS,
461
          DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
462
463
      );

464
  /**
465
   * GstDeinterlace:fields
466
467
468
469
470
   *
   * This selects which fields should be output. If "all" is selected
   * the output framerate will be double.
   *
   */
471
  g_object_class_install_property (gobject_class, PROP_FIELDS,
472
473
474
      g_param_spec_enum ("fields",
          "fields",
          "Fields to use for deinterlacing",
475
          GST_TYPE_DEINTERLACE_FIELDS,
476
          DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
477
478
      );

479
  /**
480
   * GstDeinterlace:layout
481
482
483
484
   *
   * This selects which fields is the first in time.
   *
   */
485
  g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
486
487
488
      g_param_spec_enum ("tff",
          "tff",
          "Deinterlace top field first",
489
          GST_TYPE_DEINTERLACE_FIELD_LAYOUT,
490
          DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
491
492
493
      );

  element_class->change_state =
494
      GST_DEBUG_FUNCPTR (gst_deinterlace_change_state);
495
496
}

497
static GstObject *
498
gst_deinterlace_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
499
500
    guint index)
{
501
  GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
502
503
504
505
506
507
508

  g_return_val_if_fail (index == 0, NULL);

  return gst_object_ref (self->method);
}

static guint
509
gst_deinterlace_child_proxy_get_children_count (GstChildProxy * child_proxy)
510
{
511
512
513
  GstDeinterlace *self = GST_DEINTERLACE (child_proxy);

  return ((self->method) ? 1 : 0);
514
515
516
}

static void
517
gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
518
519
520
521
    gpointer iface_data)
{
  GstChildProxyInterface *iface = g_iface;

522
523
  iface->get_child_by_index = gst_deinterlace_child_proxy_get_child_by_index;
  iface->get_children_count = gst_deinterlace_child_proxy_get_children_count;
524
525
}

526
static void
527
gst_deinterlace_init (GstDeinterlace * self, GstDeinterlaceClass * klass)
528
{
529
530
  self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
  gst_pad_set_chain_function (self->sinkpad,
531
      GST_DEBUG_FUNCPTR (gst_deinterlace_chain));
532
  gst_pad_set_event_function (self->sinkpad,
533
      GST_DEBUG_FUNCPTR (gst_deinterlace_sink_event));
534
  gst_pad_set_setcaps_function (self->sinkpad,
535
      GST_DEBUG_FUNCPTR (gst_deinterlace_setcaps));
536
  gst_pad_set_getcaps_function (self->sinkpad,
537
      GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
538
539
  gst_pad_set_query_function (self->sinkpad,
      GST_DEBUG_FUNCPTR (gst_deinterlace_sink_query));
540
541
  gst_pad_set_bufferalloc_function (self->sinkpad,
      GST_DEBUG_FUNCPTR (gst_deinterlace_alloc_buffer));
542
  gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
543

544
545
  self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
  gst_pad_set_event_function (self->srcpad,
546
      GST_DEBUG_FUNCPTR (gst_deinterlace_src_event));
547
  gst_pad_set_query_type_function (self->srcpad,
548
      GST_DEBUG_FUNCPTR (gst_deinterlace_src_query_types));
549
  gst_pad_set_query_function (self->srcpad,
550
      GST_DEBUG_FUNCPTR (gst_deinterlace_src_query));
551
  gst_pad_set_getcaps_function (self->srcpad,
552
      GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
553
554
  gst_pad_set_setcaps_function (self->srcpad,
      GST_DEBUG_FUNCPTR (gst_deinterlace_setcaps));
555
  gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
556

557
  self->mode = DEFAULT_MODE;
558
  gst_deinterlace_set_method (self, DEFAULT_METHOD);
559
560
  self->fields = DEFAULT_FIELDS;
  self->field_layout = DEFAULT_FIELD_LAYOUT;
561

562
563
  self->still_frame_mode = FALSE;

564
  gst_deinterlace_reset (self);
565
}
566

567
static void
568
gst_deinterlace_reset_history (GstDeinterlace * self)
569
570
571
{
  gint i;

572
573
  GST_DEBUG_OBJECT (self, "Resetting history");

574
575
576
577
  for (i = 0; i < self->history_count; i++) {
    if (self->field_history[i].buf) {
      gst_buffer_unref (self->field_history[i].buf);
      self->field_history[i].buf = NULL;
578
579
    }
  }
Stefan Kost's avatar
Stefan Kost committed
580
  memset (self->field_history, 0,
581
      GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
582
  self->history_count = 0;
583
584
585
586

  if (self->last_buffer)
    gst_buffer_unref (self->last_buffer);
  self->last_buffer = NULL;
587
}
588

589
590
591
592
593
594
595
596
static void
gst_deinterlace_update_passthrough (GstDeinterlace * self)
{
  self->passthrough = (self->mode == GST_DEINTERLACE_MODE_DISABLED
      || (!self->interlaced && self->mode != GST_DEINTERLACE_MODE_INTERLACED));
  GST_DEBUG_OBJECT (self, "Passthrough: %d", self->passthrough);
}

597
static void
598
gst_deinterlace_reset (GstDeinterlace * self)
599
{
600
601
  GST_DEBUG_OBJECT (self, "Resetting internal state");

602
603
604
605
606
  self->format = GST_VIDEO_FORMAT_UNKNOWN;
  self->width = 0;
  self->height = 0;
  self->frame_size = 0;
  self->fps_n = self->fps_d = 0;
607
  self->passthrough = FALSE;
608

609
  gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
610

611
612
613
614
615
616
617
618
619
620
621
622
  if (self->sink_caps)
    gst_caps_unref (self->sink_caps);
  self->sink_caps = NULL;

  if (self->src_caps)
    gst_caps_unref (self->src_caps);
  self->src_caps = NULL;

  if (self->request_caps)
    gst_caps_unref (self->request_caps);
  self->request_caps = NULL;

623
  gst_deinterlace_reset_history (self);
624
625

  gst_deinterlace_reset_qos (self);
626
627
628
}

static void
629
gst_deinterlace_set_property (GObject * object, guint prop_id,
630
631
    const GValue * value, GParamSpec * pspec)
{
632
  GstDeinterlace *self;
633

634
635
  g_return_if_fail (GST_IS_DEINTERLACE (object));
  self = GST_DEINTERLACE (object);
636
637

  switch (prop_id) {
638
639
640
641
642
643
    case PROP_MODE:{
      gint oldmode;

      GST_OBJECT_LOCK (self);
      oldmode = self->mode;
      self->mode = g_value_get_enum (value);
644
      gst_deinterlace_update_passthrough (self);
645
      if (self->mode != oldmode && GST_PAD_CAPS (self->srcpad))
646
        gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
647
      GST_OBJECT_UNLOCK (self);
648
      break;
649
    }
650
    case PROP_METHOD:
651
      gst_deinterlace_set_method (self, g_value_get_enum (value));
652
      break;
653
    case PROP_FIELDS:{
654
655
      gint oldfields;

656
657
658
659
      GST_OBJECT_LOCK (self);
      oldfields = self->fields;
      self->fields = g_value_get_enum (value);
      if (self->fields != oldfields && GST_PAD_CAPS (self->srcpad))
660
        gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
661
      GST_OBJECT_UNLOCK (self);
662
      break;
663
    }
664
    case PROP_FIELD_LAYOUT:
665
      self->field_layout = g_value_get_enum (value);
666
667
      break;
    default:
668
      G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
669
670
671
672
673
  }

}

static void
674
gst_deinterlace_get_property (GObject * object, guint prop_id,
675
676
    GValue * value, GParamSpec * pspec)
{
677
  GstDeinterlace *self;
678

679
680
  g_return_if_fail (GST_IS_DEINTERLACE (object));
  self = GST_DEINTERLACE (object);
681
682

  switch (prop_id) {
683
684
685
    case PROP_MODE:
      g_value_set_enum (value, self->mode);
      break;
686
    case PROP_METHOD:
687
      g_value_set_enum (value, self->method_id);
688
      break;
689
    case PROP_FIELDS:
690
      g_value_set_enum (value, self->fields);
691
      break;
692
    case PROP_FIELD_LAYOUT:
693
      g_value_set_enum (value, self->field_layout);
694
695
      break;
    default:
696
      G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
697
698
699
700
  }
}

static void
701
gst_deinterlace_finalize (GObject * object)
702
{
703
  GstDeinterlace *self = GST_DEINTERLACE (object);
704

705
  gst_deinterlace_reset (self);
706
707
708
709
710

  if (self->method) {
    gst_object_unparent (GST_OBJECT (self->method));
    self->method = NULL;
  }
711
712

  G_OBJECT_CLASS (parent_class)->finalize (object);
713
714
715
}

static GstBuffer *
716
gst_deinterlace_pop_history (GstDeinterlace * self)
717
{
718
719
720
  GstBuffer *buffer;

  g_return_val_if_fail (self->history_count > 0, NULL);
721

722
723
  GST_DEBUG_OBJECT (self, "Pop last history buffer -- current history size %d",
      self->history_count);
724

725
  buffer = self->field_history[self->history_count - 1].buf;
726

727
  self->history_count--;
728

729
730
731
732
  GST_DEBUG_OBJECT (self, "Returning buffer: %" GST_TIME_FORMAT
      " with duration %" GST_TIME_FORMAT " and size %u",
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
      GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
733

734
  return buffer;
735
736
737
}

static void
738
gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
739
740
741
{
  int i = 1;
  GstClockTime timestamp;
742
  GstDeinterlaceFieldLayout field_layout = self->field_layout;
743
744
745
746
747
748
749
750
  gboolean repeated = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF);
  gboolean tff = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF);
  gboolean onefield =
      GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD);
  GstBuffer *field1, *field2;
  guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3;
  gint field1_flags, field2_flags;

Stefan Kost's avatar
Stefan Kost committed
751
752
  g_return_if_fail (self->history_count <
      GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
753
754
755
756
757

  GST_DEBUG_OBJECT (self, "Pushing new buffer to the history: %" GST_TIME_FORMAT
      " with duration %" GST_TIME_FORMAT " and size %u",
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
      GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
758

Stefan Kost's avatar
Stefan Kost committed
759
  for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
760
761
762
    self->field_history[i].buf = self->field_history[i - fields_to_push].buf;
    self->field_history[i].flags =
        self->field_history[i - fields_to_push].flags;
763
764
  }

765
  if (field_layout == GST_DEINTERLACE_LAYOUT_AUTO) {
766
767
    if (!self->interlaced) {
      GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
768
      field_layout = GST_DEINTERLACE_LAYOUT_TFF;
769
    } else if (tff) {
770
      field_layout = GST_DEINTERLACE_LAYOUT_TFF;
771
    } else {
772
      field_layout = GST_DEINTERLACE_LAYOUT_BFF;
773
    }
774
775
  }

776
  if (field_layout == GST_DEINTERLACE_LAYOUT_TFF) {
777
    GST_DEBUG_OBJECT (self, "Top field first");
778
779
    field1 = gst_buffer_ref (buffer);
    field1_flags = PICTURE_INTERLACED_TOP;
780
    field2 = gst_buffer_ref (buffer);
781
    field2_flags = PICTURE_INTERLACED_BOTTOM;
782
  } else {
783
    GST_DEBUG_OBJECT (self, "Bottom field first");
784
    field1 = gst_buffer_ref (buffer);
785
786
787
    field1_flags = PICTURE_INTERLACED_BOTTOM;
    field2 = gst_buffer_ref (buffer);
    field2_flags = PICTURE_INTERLACED_TOP;
788
789
790
791
792
793
  }

  /* Timestamps are assigned to the field buffers under the assumption that
     the timestamp of the buffer equals the first fields timestamp */

  timestamp = GST_BUFFER_TIMESTAMP (buffer);
794
795
796
797
  GST_BUFFER_TIMESTAMP (field1) = timestamp;
  GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration;
  if (repeated)
    GST_BUFFER_TIMESTAMP (field2) += self->field_duration;
798

799
800
801
802
  if (repeated) {
    self->field_history[0].buf = field2;
    self->field_history[0].flags = field2_flags;
    self->field_history[1].buf = gst_buffer_ref (field1);
803
    GST_BUFFER_TIMESTAMP (self->field_history[1].buf) += self->field_duration;
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
    self->field_history[1].flags = field1_flags;
    self->field_history[2].buf = field1;
    self->field_history[2].flags = field1_flags;
  } else if (!onefield) {
    self->field_history[0].buf = field2;
    self->field_history[0].flags = field2_flags;
    self->field_history[1].buf = field1;
    self->field_history[1].flags = field1_flags;
  } else {                      /* onefield */
    self->field_history[0].buf = field1;
    self->field_history[0].flags = field1_flags;
    gst_buffer_unref (field2);
  }

  self->history_count += fields_to_push;
819
820
821

  GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d",
      self->history_count);
822

823
824
825
  if (self->last_buffer)
    gst_buffer_unref (self->last_buffer);
  self->last_buffer = buffer;
826
827
}

828
829
static void
gst_deinterlace_update_qos (GstDeinterlace * self, gdouble proportion,
830
    GstClockTimeDiff diff, GstClockTime timestamp)
831
{
832
833
834
835
836
  GST_DEBUG_OBJECT (self,
      "Updating QoS: proportion %lf, diff %s%" GST_TIME_FORMAT ", timestamp %"
      GST_TIME_FORMAT, proportion, (diff < 0) ? "-" : "",
      GST_TIME_ARGS (ABS (diff)), GST_TIME_ARGS (timestamp));

837
838
839
840
  GST_OBJECT_LOCK (self);
  self->proportion = proportion;
  if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
    if (G_UNLIKELY (diff > 0))
841
842
843
844
      self->earliest_time =
          timestamp + 2 * diff + ((self->fields ==
              GST_DEINTERLACE_ALL) ? self->field_duration : 2 *
          self->field_duration);
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
    else
      self->earliest_time = timestamp + diff;
  } else {
    self->earliest_time = GST_CLOCK_TIME_NONE;
  }
  GST_OBJECT_UNLOCK (self);
}

static void
gst_deinterlace_reset_qos (GstDeinterlace * self)
{
  gst_deinterlace_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
}

static void
gst_deinterlace_read_qos (GstDeinterlace * self, gdouble * proportion,
    GstClockTime * time)
{
  GST_OBJECT_LOCK (self);
  *proportion = self->proportion;
  *time = self->earliest_time;
  GST_OBJECT_UNLOCK (self);
}

/* Perform qos calculations before processing the next frame. Returns TRUE if
 * the frame should be processed, FALSE if the frame can be dropped entirely */
static gboolean
gst_deinterlace_do_qos (GstDeinterlace * self, GstClockTime timestamp)
{
  GstClockTime qostime, earliest_time;
  gdouble proportion;

  /* no timestamp, can't do QoS => process frame */
  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
    GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
    return TRUE;
  }

  /* get latest QoS observation values */
  gst_deinterlace_read_qos (self, &proportion, &earliest_time);

  /* skip qos if we have no observation (yet) => process frame */
  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
    GST_LOG_OBJECT (self, "no observation yet, process frame");
    return TRUE;
  }

  /* qos is done on running time */
  qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
      timestamp);

  /* see how our next timestamp relates to the latest qos timestamp */
  GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
      GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));

  if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
    GST_DEBUG_OBJECT (self, "we are late, drop frame");
    return FALSE;
  }

  GST_LOG_OBJECT (self, "process frame");
  return TRUE;
}

909
static GstFlowReturn
910
gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
911
{
912
  GstDeinterlace *self = GST_DEINTERLACE (GST_PAD_PARENT (pad));
913
  GstClockTime timestamp;
914
  GstFlowReturn ret = GST_FLOW_OK;
915
  gint fields_required = 0;
916
  gint cur_field_idx = 0;
917
  GstBuffer *outbuf;
918

919
  if (self->still_frame_mode || self->passthrough)
920
921
    return gst_pad_push (self->srcpad, buf);

922
923
  if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
    GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
924
    gst_deinterlace_reset_history (self);
925
926
  }

927
  gst_deinterlace_push_history (self, buf);
928
929
  buf = NULL;

930
  fields_required = gst_deinterlace_method_get_fields_required (self->method);
931

932
  /* Not enough fields in the history */
933
  if (self->history_count < fields_required + 1) {
934
935
    GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
        self->history_count, fields_required + 1);
936
937
    return GST_FLOW_OK;
  }
938

939
  while (self->history_count >= fields_required) {
940
    if (self->fields == GST_DEINTERLACE_ALL)
941
      GST_DEBUG_OBJECT (self, "All fields");
942
    else if (self->fields == GST_DEINTERLACE_TF)
943
      GST_DEBUG_OBJECT (self, "Top fields");
944
    else if (self->fields == GST_DEINTERLACE_BF)
945
      GST_DEBUG_OBJECT (self, "Bottom fields");
946

947
    cur_field_idx = self->history_count - fields_required;
948

949
    if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP
950
951
            && self->fields == GST_DEINTERLACE_TF) ||
        self->fields == GST_DEINTERLACE_ALL) {
952
      GST_DEBUG_OBJECT (self, "deinterlacing top field");
953
954

      /* create new buffer */
955
956
      ret = gst_pad_alloc_buffer (self->srcpad,
          GST_BUFFER_OFFSET_NONE, self->frame_size, self->src_caps, &outbuf);
957
958
      if (ret != GST_FLOW_OK)
        return ret;
959

960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
      if (self->src_caps != GST_BUFFER_CAPS (outbuf) &&
          !gst_caps_is_equal (self->src_caps, GST_BUFFER_CAPS (outbuf))) {
        gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
        GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
            self->request_caps);

        gst_buffer_unref (outbuf);
        outbuf = gst_buffer_try_new_and_alloc (self->frame_size);

        if (!outbuf)
          return GST_FLOW_ERROR;

        gst_buffer_set_caps (outbuf, self->src_caps);
      }

975
976
977
978
      g_return_val_if_fail (self->history_count - 1 -
          gst_deinterlace_method_get_latency (self->method) >= 0,
          GST_FLOW_ERROR);

979
980
981
      buf =
          self->field_history[self->history_count - 1 -
          gst_deinterlace_method_get_latency (self->method)].buf;
982
      timestamp = GST_BUFFER_TIMESTAMP (buf);
983

984
      GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
985
      if (self->fields == GST_DEINTERLACE_ALL)
986
        GST_BUFFER_DURATION (outbuf) = self->field_duration;
987
      else
988
        GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
989

990
991
992
993
994
995
996
997
      /* Check if we need to drop the frame because of QoS */
      if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
        gst_buffer_unref (gst_deinterlace_pop_history (self));
        gst_buffer_unref (outbuf);
        outbuf = NULL;
        ret = GST_FLOW_OK;
      } else {
        /* do magic calculus */
998
999