• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2008-2010 Sebastian Dröge <slomo@collabora.co.uk>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <string.h>
26 
27 #include "gstdeinterlacemethod.h"
28 
29 G_DEFINE_ABSTRACT_TYPE (GstDeinterlaceMethod, gst_deinterlace_method,
30     GST_TYPE_OBJECT);
31 
32 gboolean
gst_deinterlace_method_supported(GType type,GstVideoFormat format,gint width,gint height)33 gst_deinterlace_method_supported (GType type, GstVideoFormat format, gint width,
34     gint height)
35 {
36   GstDeinterlaceMethodClass *klass =
37       GST_DEINTERLACE_METHOD_CLASS (g_type_class_ref (type));
38   gboolean ret;
39 
40   if (format == GST_VIDEO_FORMAT_UNKNOWN)
41     ret = TRUE;
42   else
43     ret = klass->supported (klass, format, width, height);
44   g_type_class_unref (klass);
45 
46   return ret;
47 }
48 
49 static gboolean
gst_deinterlace_method_supported_impl(GstDeinterlaceMethodClass * klass,GstVideoFormat format,gint width,gint height)50 gst_deinterlace_method_supported_impl (GstDeinterlaceMethodClass * klass,
51     GstVideoFormat format, gint width, gint height)
52 {
53   switch (format) {
54     case GST_VIDEO_FORMAT_YUY2:
55       return (klass->deinterlace_frame_yuy2 != NULL);
56     case GST_VIDEO_FORMAT_YVYU:
57       return (klass->deinterlace_frame_yvyu != NULL);
58     case GST_VIDEO_FORMAT_UYVY:
59       return (klass->deinterlace_frame_uyvy != NULL);
60     case GST_VIDEO_FORMAT_I420:
61       return (klass->deinterlace_frame_i420 != NULL);
62     case GST_VIDEO_FORMAT_YV12:
63       return (klass->deinterlace_frame_yv12 != NULL);
64     case GST_VIDEO_FORMAT_Y444:
65       return (klass->deinterlace_frame_y444 != NULL);
66     case GST_VIDEO_FORMAT_Y42B:
67       return (klass->deinterlace_frame_y42b != NULL);
68     case GST_VIDEO_FORMAT_Y41B:
69       return (klass->deinterlace_frame_y41b != NULL);
70     case GST_VIDEO_FORMAT_AYUV:
71       return (klass->deinterlace_frame_ayuv != NULL);
72     case GST_VIDEO_FORMAT_NV12:
73       return (klass->deinterlace_frame_nv12 != NULL);
74     case GST_VIDEO_FORMAT_NV21:
75       return (klass->deinterlace_frame_nv21 != NULL);
76     case GST_VIDEO_FORMAT_ARGB:
77     case GST_VIDEO_FORMAT_xRGB:
78       return (klass->deinterlace_frame_argb != NULL);
79     case GST_VIDEO_FORMAT_ABGR:
80     case GST_VIDEO_FORMAT_xBGR:
81       return (klass->deinterlace_frame_abgr != NULL);
82     case GST_VIDEO_FORMAT_RGBA:
83     case GST_VIDEO_FORMAT_RGBx:
84       return (klass->deinterlace_frame_rgba != NULL);
85     case GST_VIDEO_FORMAT_BGRA:
86     case GST_VIDEO_FORMAT_BGRx:
87       return (klass->deinterlace_frame_bgra != NULL);
88     case GST_VIDEO_FORMAT_RGB:
89       return (klass->deinterlace_frame_rgb != NULL);
90     case GST_VIDEO_FORMAT_BGR:
91       return (klass->deinterlace_frame_bgr != NULL);
92     default:
93       return FALSE;
94   }
95 }
96 
97 void
gst_deinterlace_method_setup(GstDeinterlaceMethod * self,GstVideoInfo * vinfo)98 gst_deinterlace_method_setup (GstDeinterlaceMethod * self, GstVideoInfo * vinfo)
99 {
100   GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
101 
102   klass->setup (self, vinfo);
103 }
104 
105 static void
gst_deinterlace_method_setup_impl(GstDeinterlaceMethod * self,GstVideoInfo * vinfo)106 gst_deinterlace_method_setup_impl (GstDeinterlaceMethod * self,
107     GstVideoInfo * vinfo)
108 {
109   GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
110 
111   self->vinfo = vinfo;
112 
113   self->deinterlace_frame = NULL;
114 
115   if (GST_VIDEO_INFO_FORMAT (self->vinfo) == GST_VIDEO_FORMAT_UNKNOWN)
116     return;
117 
118   switch (GST_VIDEO_INFO_FORMAT (self->vinfo)) {
119     case GST_VIDEO_FORMAT_YUY2:
120       self->deinterlace_frame = klass->deinterlace_frame_yuy2;
121       break;
122     case GST_VIDEO_FORMAT_YVYU:
123       self->deinterlace_frame = klass->deinterlace_frame_yvyu;
124       break;
125     case GST_VIDEO_FORMAT_UYVY:
126       self->deinterlace_frame = klass->deinterlace_frame_uyvy;
127       break;
128     case GST_VIDEO_FORMAT_I420:
129       self->deinterlace_frame = klass->deinterlace_frame_i420;
130       break;
131     case GST_VIDEO_FORMAT_YV12:
132       self->deinterlace_frame = klass->deinterlace_frame_yv12;
133       break;
134     case GST_VIDEO_FORMAT_Y444:
135       self->deinterlace_frame = klass->deinterlace_frame_y444;
136       break;
137     case GST_VIDEO_FORMAT_Y42B:
138       self->deinterlace_frame = klass->deinterlace_frame_y42b;
139       break;
140     case GST_VIDEO_FORMAT_Y41B:
141       self->deinterlace_frame = klass->deinterlace_frame_y41b;
142       break;
143     case GST_VIDEO_FORMAT_AYUV:
144       self->deinterlace_frame = klass->deinterlace_frame_ayuv;
145       break;
146     case GST_VIDEO_FORMAT_NV12:
147       self->deinterlace_frame = klass->deinterlace_frame_nv12;
148       break;
149     case GST_VIDEO_FORMAT_NV21:
150       self->deinterlace_frame = klass->deinterlace_frame_nv21;
151       break;
152     case GST_VIDEO_FORMAT_ARGB:
153     case GST_VIDEO_FORMAT_xRGB:
154       self->deinterlace_frame = klass->deinterlace_frame_argb;
155       break;
156     case GST_VIDEO_FORMAT_ABGR:
157     case GST_VIDEO_FORMAT_xBGR:
158       self->deinterlace_frame = klass->deinterlace_frame_abgr;
159       break;
160     case GST_VIDEO_FORMAT_RGBA:
161     case GST_VIDEO_FORMAT_RGBx:
162       self->deinterlace_frame = klass->deinterlace_frame_rgba;
163       break;
164     case GST_VIDEO_FORMAT_BGRA:
165     case GST_VIDEO_FORMAT_BGRx:
166       self->deinterlace_frame = klass->deinterlace_frame_bgra;
167       break;
168     case GST_VIDEO_FORMAT_RGB:
169       self->deinterlace_frame = klass->deinterlace_frame_rgb;
170       break;
171     case GST_VIDEO_FORMAT_BGR:
172       self->deinterlace_frame = klass->deinterlace_frame_bgr;
173       break;
174     default:
175       self->deinterlace_frame = NULL;
176       break;
177   }
178 }
179 
180 static void
gst_deinterlace_method_class_init(GstDeinterlaceMethodClass * klass)181 gst_deinterlace_method_class_init (GstDeinterlaceMethodClass * klass)
182 {
183   klass->setup = gst_deinterlace_method_setup_impl;
184   klass->supported = gst_deinterlace_method_supported_impl;
185 }
186 
187 static void
gst_deinterlace_method_init(GstDeinterlaceMethod * self)188 gst_deinterlace_method_init (GstDeinterlaceMethod * self)
189 {
190   self->vinfo = NULL;
191 }
192 
193 void
gst_deinterlace_method_deinterlace_frame(GstDeinterlaceMethod * self,const GstDeinterlaceField * history,guint history_count,GstVideoFrame * outframe,int cur_field_idx)194 gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self,
195     const GstDeinterlaceField * history, guint history_count,
196     GstVideoFrame * outframe, int cur_field_idx)
197 {
198   g_assert (self->deinterlace_frame != NULL);
199   self->deinterlace_frame (self, history, history_count, outframe,
200       cur_field_idx);
201 }
202 
203 gint
gst_deinterlace_method_get_fields_required(GstDeinterlaceMethod * self)204 gst_deinterlace_method_get_fields_required (GstDeinterlaceMethod * self)
205 {
206   GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
207 
208   return klass->fields_required;
209 }
210 
211 gint
gst_deinterlace_method_get_latency(GstDeinterlaceMethod * self)212 gst_deinterlace_method_get_latency (GstDeinterlaceMethod * self)
213 {
214   GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
215 
216   return klass->latency;
217 }
218 
219 G_DEFINE_ABSTRACT_TYPE (GstDeinterlaceSimpleMethod,
220     gst_deinterlace_simple_method, GST_TYPE_DEINTERLACE_METHOD);
221 
222 static gboolean
gst_deinterlace_simple_method_supported(GstDeinterlaceMethodClass * mklass,GstVideoFormat format,gint width,gint height)223 gst_deinterlace_simple_method_supported (GstDeinterlaceMethodClass * mklass,
224     GstVideoFormat format, gint width, gint height)
225 {
226   GstDeinterlaceSimpleMethodClass *klass =
227       GST_DEINTERLACE_SIMPLE_METHOD_CLASS (mklass);
228 
229   if (!GST_DEINTERLACE_METHOD_CLASS
230       (gst_deinterlace_simple_method_parent_class)->supported (mklass, format,
231           width, height))
232     return FALSE;
233 
234   switch (format) {
235     case GST_VIDEO_FORMAT_ARGB:
236     case GST_VIDEO_FORMAT_xRGB:
237       return (klass->interpolate_scanline_argb != NULL
238           && klass->copy_scanline_argb != NULL);
239     case GST_VIDEO_FORMAT_RGBA:
240     case GST_VIDEO_FORMAT_RGBx:
241       return (klass->interpolate_scanline_rgba != NULL
242           && klass->copy_scanline_rgba != NULL);
243     case GST_VIDEO_FORMAT_ABGR:
244     case GST_VIDEO_FORMAT_xBGR:
245       return (klass->interpolate_scanline_abgr != NULL
246           && klass->copy_scanline_abgr != NULL);
247     case GST_VIDEO_FORMAT_BGRA:
248     case GST_VIDEO_FORMAT_BGRx:
249       return (klass->interpolate_scanline_bgra != NULL
250           && klass->copy_scanline_bgra != NULL);
251     case GST_VIDEO_FORMAT_RGB:
252       return (klass->interpolate_scanline_rgb != NULL
253           && klass->copy_scanline_rgb != NULL);
254     case GST_VIDEO_FORMAT_BGR:
255       return (klass->interpolate_scanline_bgr != NULL
256           && klass->copy_scanline_bgr != NULL);
257     case GST_VIDEO_FORMAT_YUY2:
258       return (klass->interpolate_scanline_yuy2 != NULL
259           && klass->copy_scanline_yuy2 != NULL);
260     case GST_VIDEO_FORMAT_YVYU:
261       return (klass->interpolate_scanline_yvyu != NULL
262           && klass->copy_scanline_yvyu != NULL);
263     case GST_VIDEO_FORMAT_UYVY:
264       return (klass->interpolate_scanline_uyvy != NULL
265           && klass->copy_scanline_uyvy != NULL);
266     case GST_VIDEO_FORMAT_AYUV:
267       return (klass->interpolate_scanline_ayuv != NULL
268           && klass->copy_scanline_ayuv != NULL);
269     case GST_VIDEO_FORMAT_NV12:
270       return (klass->interpolate_scanline_nv12 != NULL
271           && klass->copy_scanline_nv12 != NULL
272           && klass->interpolate_scanline_planar_y != NULL
273           && klass->copy_scanline_planar_y != NULL);
274     case GST_VIDEO_FORMAT_NV21:
275       return (klass->interpolate_scanline_nv21 != NULL
276           && klass->copy_scanline_nv21 != NULL
277           && klass->interpolate_scanline_planar_y != NULL
278           && klass->copy_scanline_planar_y != NULL);
279     case GST_VIDEO_FORMAT_I420:
280     case GST_VIDEO_FORMAT_YV12:
281     case GST_VIDEO_FORMAT_Y444:
282     case GST_VIDEO_FORMAT_Y42B:
283     case GST_VIDEO_FORMAT_Y41B:
284       return (klass->interpolate_scanline_planar_y != NULL
285           && klass->copy_scanline_planar_y != NULL &&
286           klass->interpolate_scanline_planar_u != NULL
287           && klass->copy_scanline_planar_u != NULL &&
288           klass->interpolate_scanline_planar_v != NULL
289           && klass->copy_scanline_planar_v != NULL);
290     default:
291       return FALSE;
292   }
293 }
294 
295 static void
gst_deinterlace_simple_method_interpolate_scanline_packed(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint stride)296     gst_deinterlace_simple_method_interpolate_scanline_packed
297     (GstDeinterlaceSimpleMethod * self, guint8 * out,
298     const GstDeinterlaceScanlineData * scanlines, guint stride)
299 {
300   memcpy (out, scanlines->m1, stride);
301 }
302 
303 static void
gst_deinterlace_simple_method_copy_scanline_packed(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint stride)304 gst_deinterlace_simple_method_copy_scanline_packed (GstDeinterlaceSimpleMethod *
305     self, guint8 * out, const GstDeinterlaceScanlineData * scanlines,
306     guint stride)
307 {
308   memcpy (out, scanlines->m0, stride);
309 }
310 
311 typedef struct
312 {
313   const GstDeinterlaceField *history;
314   guint history_count;
315   gint cur_field_idx;
316 } LinesGetter;
317 
318 #define CLAMP_LOW(i) (((i)<0) ? (i+2) : (i))
319 #define CLAMP_HI(i) (((i)>=(frame_height)) ? (i-2) : (i))
320 
321 static guint8 *
get_line(LinesGetter * lg,gint field_offset,guint plane,gint line,gint line_offset)322 get_line (LinesGetter * lg, gint field_offset, guint plane, gint line,
323     gint line_offset)
324 {
325   const GstVideoFrame *frame;
326   gint idx, frame_height;
327   guint8 *data;
328 
329   idx = lg->cur_field_idx + field_offset;
330   if (idx < 0 || idx >= lg->history_count)
331     return NULL;
332 
333   frame = lg->history[idx].frame;
334   g_assert (frame);
335 
336   /* Now frame already refers to the field we want, the correct one is taken
337    * from the history */
338   if (GST_VIDEO_INFO_INTERLACE_MODE (&frame->info) ==
339       GST_VIDEO_INTERLACE_MODE_ALTERNATE) {
340     /* Alternate frame containing a single field, adjust the line index */
341     line /= 2;
342     switch (line_offset) {
343       case -2:
344       case 2:
345         line_offset /= 2;
346         break;
347       case 1:
348         /* the "next" line of a top field line is the same line of a bottom
349          * field */
350         if (!GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_VIDEO_FRAME_FLAG_TFF))
351           line_offset = 0;
352         break;
353       case -1:
354         /* the "previous" line of a bottom field line is the same line of a
355          * top field */
356         if (GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_VIDEO_FRAME_FLAG_TFF))
357           line_offset = 0;
358         break;
359       case 0:
360         break;
361       default:
362         g_assert_not_reached ();
363         break;
364     }
365   }
366 
367   frame_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, plane);
368   line += line_offset;
369 
370   data = GST_VIDEO_FRAME_PLANE_DATA ((frame), plane);
371   data += CLAMP_HI (CLAMP_LOW (line)) * GST_VIDEO_FRAME_PLANE_STRIDE ((frame),
372       plane);
373 
374   return data;
375 }
376 
377 static void
gst_deinterlace_simple_method_deinterlace_frame_packed(GstDeinterlaceMethod * method,const GstDeinterlaceField * history,guint history_count,GstVideoFrame * outframe,gint cur_field_idx)378 gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod *
379     method, const GstDeinterlaceField * history, guint history_count,
380     GstVideoFrame * outframe, gint cur_field_idx)
381 {
382   GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
383 #ifndef G_DISABLE_ASSERT
384   GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self);
385 #endif
386   GstDeinterlaceScanlineData scanlines;
387   guint cur_field_flags;
388   gint i;
389   gint frame_height, frame_width;
390   LinesGetter lg = { history, history_count, cur_field_idx };
391   GstVideoFrame *framep, *frame0, *frame1, *frame2;
392 
393   g_assert (self->interpolate_scanline_packed != NULL);
394   g_assert (self->copy_scanline_packed != NULL);
395 
396   frame_height = GST_VIDEO_FRAME_HEIGHT (outframe);
397   frame_width = GST_VIDEO_FRAME_PLANE_STRIDE (outframe, 0);
398 
399   frame0 = history[cur_field_idx].frame;
400   frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (frame0, 0));
401   cur_field_flags = history[cur_field_idx].flags;
402 
403   framep = (cur_field_idx > 0 ? history[cur_field_idx - 1].frame : NULL);
404   if (framep)
405     frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (framep, 0));
406 
407   g_assert (dm_class->fields_required <= 5);
408 
409   frame1 =
410       (cur_field_idx + 1 <
411       history_count ? history[cur_field_idx + 1].frame : NULL);
412   if (frame1)
413     frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (frame1, 0));
414 
415   frame2 =
416       (cur_field_idx + 2 <
417       history_count ? history[cur_field_idx + 2].frame : NULL);
418   if (frame2)
419     frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (frame2, 0));
420 
421 #define LINE(x,i) (((guint8*)GST_VIDEO_FRAME_PLANE_DATA((x),0)) + i * \
422     GST_VIDEO_FRAME_PLANE_STRIDE((x),0))
423 
424   for (i = 0; i < frame_height; i++) {
425     memset (&scanlines, 0, sizeof (scanlines));
426     scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
427 
428     if (!((i & 1) ^ scanlines.bottom_field)) {
429       /* copying */
430       scanlines.tp = get_line (&lg, -1, 0, i, -1);
431       scanlines.bp = get_line (&lg, -1, 0, i, 1);
432 
433       scanlines.tt0 = get_line (&lg, 0, 0, i, -2);
434       scanlines.m0 = get_line (&lg, 0, 0, i, 0);
435       scanlines.bb0 = get_line (&lg, 0, 0, i, 2);
436 
437       scanlines.t1 = get_line (&lg, 1, 0, i, -1);
438       scanlines.b1 = get_line (&lg, 1, 0, i, 1);
439 
440       scanlines.tt2 = get_line (&lg, 2, 0, i, -2);
441       scanlines.m2 = get_line (&lg, 2, 0, i, 0);
442       scanlines.bb2 = get_line (&lg, 2, 0, i, 2);
443 
444       self->copy_scanline_packed (self, LINE (outframe, i), &scanlines,
445           frame_width);
446     } else {
447       /* interpolating */
448       scanlines.tp2 = get_line (&lg, -2, 0, i, -1);
449       scanlines.bp2 = get_line (&lg, -2, 0, i, 1);
450 
451       scanlines.ttp = get_line (&lg, -1, 0, i, -2);
452       scanlines.mp = get_line (&lg, -1, 0, i, 0);
453       scanlines.bbp = get_line (&lg, -1, 0, i, 2);
454 
455       scanlines.t0 = get_line (&lg, 0, 0, i, -1);
456       scanlines.b0 = get_line (&lg, 0, 0, i, 1);
457 
458       scanlines.tt1 = get_line (&lg, 1, 0, i, -2);
459       scanlines.m1 = get_line (&lg, 1, 0, i, 0);
460       scanlines.bb1 = get_line (&lg, 1, 0, i, 2);
461 
462       scanlines.t2 = get_line (&lg, 2, 0, i, -1);
463       scanlines.b2 = get_line (&lg, 2, 0, i, 1);
464 
465       self->interpolate_scanline_packed (self, LINE (outframe, i), &scanlines,
466           frame_width);
467     }
468 #undef LINE
469   }
470 }
471 
472 static void
gst_deinterlace_simple_method_interpolate_scanline_planar_y(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)473     gst_deinterlace_simple_method_interpolate_scanline_planar_y
474     (GstDeinterlaceSimpleMethod * self, guint8 * out,
475     const GstDeinterlaceScanlineData * scanlines, guint size)
476 {
477   memcpy (out, scanlines->m1, size);
478 }
479 
480 static void
gst_deinterlace_simple_method_copy_scanline_planar_y(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)481 gst_deinterlace_simple_method_copy_scanline_planar_y (GstDeinterlaceSimpleMethod
482     * self, guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint
483     size)
484 {
485   memcpy (out, scanlines->m0, size);
486 }
487 
488 static void
gst_deinterlace_simple_method_interpolate_scanline_planar_u(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)489     gst_deinterlace_simple_method_interpolate_scanline_planar_u
490     (GstDeinterlaceSimpleMethod * self, guint8 * out,
491     const GstDeinterlaceScanlineData * scanlines, guint size)
492 {
493   memcpy (out, scanlines->m1, size);
494 }
495 
496 static void
gst_deinterlace_simple_method_copy_scanline_planar_u(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)497 gst_deinterlace_simple_method_copy_scanline_planar_u (GstDeinterlaceSimpleMethod
498     * self, guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint
499     size)
500 {
501   memcpy (out, scanlines->m0, size);
502 }
503 
504 static void
gst_deinterlace_simple_method_interpolate_scanline_planar_v(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)505     gst_deinterlace_simple_method_interpolate_scanline_planar_v
506     (GstDeinterlaceSimpleMethod * self, guint8 * out,
507     const GstDeinterlaceScanlineData * scanlines, guint size)
508 {
509   memcpy (out, scanlines->m1, size);
510 }
511 
512 static void
gst_deinterlace_simple_method_copy_scanline_planar_v(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)513 gst_deinterlace_simple_method_copy_scanline_planar_v (GstDeinterlaceSimpleMethod
514     * self, guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint
515     size)
516 {
517   memcpy (out, scanlines->m0, size);
518 }
519 
520 static void
gst_deinterlace_simple_method_deinterlace_frame_planar_plane(GstDeinterlaceSimpleMethod * self,GstVideoFrame * dest,LinesGetter * lg,guint cur_field_flags,gint plane,GstDeinterlaceSimpleMethodFunction copy_scanline,GstDeinterlaceSimpleMethodFunction interpolate_scanline)521     gst_deinterlace_simple_method_deinterlace_frame_planar_plane
522     (GstDeinterlaceSimpleMethod * self, GstVideoFrame * dest,
523     LinesGetter * lg,
524     guint cur_field_flags, gint plane,
525     GstDeinterlaceSimpleMethodFunction copy_scanline,
526     GstDeinterlaceSimpleMethodFunction interpolate_scanline)
527 {
528   GstDeinterlaceScanlineData scanlines;
529   gint i;
530   gint frame_height, frame_width;
531 
532   frame_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, plane);
533   frame_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, plane) *
534       GST_VIDEO_FRAME_COMP_PSTRIDE (dest, plane);
535 
536   g_assert (interpolate_scanline != NULL);
537   g_assert (copy_scanline != NULL);
538 
539 #define LINE(x,i) (((guint8*)GST_VIDEO_FRAME_PLANE_DATA((x),plane)) + i * \
540     GST_VIDEO_FRAME_PLANE_STRIDE((x),plane))
541 
542   for (i = 0; i < frame_height; i++) {
543     memset (&scanlines, 0, sizeof (scanlines));
544     scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
545 
546     if (!((i & 1) ^ scanlines.bottom_field)) {
547       /* copying */
548       scanlines.tp = get_line (lg, -1, plane, i, -1);
549       scanlines.bp = get_line (lg, -1, plane, i, 1);
550 
551       scanlines.tt0 = get_line (lg, 0, plane, i, -2);
552       scanlines.m0 = get_line (lg, 0, plane, i, 0);
553       scanlines.bb0 = get_line (lg, 0, plane, i, 2);
554 
555       scanlines.t1 = get_line (lg, 1, plane, i, -1);
556       scanlines.b1 = get_line (lg, 1, plane, i, 1);
557 
558       scanlines.tt2 = get_line (lg, 2, plane, i, -2);
559       scanlines.m2 = get_line (lg, 2, plane, i, 0);
560       scanlines.bb2 = get_line (lg, 2, plane, i, 2);
561 
562       copy_scanline (self, LINE (dest, i), &scanlines, frame_width);
563     } else {
564       /* interpolating */
565       scanlines.tp2 = get_line (lg, -2, plane, i, -1);
566       scanlines.bp2 = get_line (lg, -2, plane, i, 1);
567 
568       scanlines.ttp = get_line (lg, -1, plane, i, -2);
569       scanlines.mp = get_line (lg, -1, plane, i, 0);
570       scanlines.bbp = get_line (lg, -1, plane, i, 2);
571 
572       scanlines.t0 = get_line (lg, 0, plane, i, -1);
573       scanlines.b0 = get_line (lg, 0, plane, i, 1);
574 
575       scanlines.tt1 = get_line (lg, 1, plane, i, -2);
576       scanlines.m1 = get_line (lg, 1, plane, i, 0);
577       scanlines.bb1 = get_line (lg, 1, plane, i, 2);
578 
579       scanlines.t2 = get_line (lg, 2, plane, i, -1);
580       scanlines.b2 = get_line (lg, 2, plane, i, 1);
581 
582       interpolate_scanline (self, LINE (dest, i), &scanlines, frame_width);
583     }
584 #undef LINE
585   }
586 }
587 
588 static void
gst_deinterlace_simple_method_deinterlace_frame_planar(GstDeinterlaceMethod * method,const GstDeinterlaceField * history,guint history_count,GstVideoFrame * outframe,gint cur_field_idx)589 gst_deinterlace_simple_method_deinterlace_frame_planar (GstDeinterlaceMethod *
590     method, const GstDeinterlaceField * history, guint history_count,
591     GstVideoFrame * outframe, gint cur_field_idx)
592 {
593   GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
594 #ifndef G_DISABLE_ASSERT
595   GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self);
596 #endif
597   guint cur_field_flags = history[cur_field_idx].flags;
598   gint i;
599   GstDeinterlaceSimpleMethodFunction copy_scanline;
600   GstDeinterlaceSimpleMethodFunction interpolate_scanline;
601   LinesGetter lg = { history, history_count, cur_field_idx };
602 
603   g_assert (self->interpolate_scanline_planar[0] != NULL);
604   g_assert (self->interpolate_scanline_planar[1] != NULL);
605   g_assert (self->interpolate_scanline_planar[2] != NULL);
606   g_assert (self->copy_scanline_planar[0] != NULL);
607   g_assert (self->copy_scanline_planar[1] != NULL);
608   g_assert (self->copy_scanline_planar[2] != NULL);
609   g_assert (dm_class->fields_required <= 5);
610 
611   for (i = 0; i < 3; i++) {
612     copy_scanline = self->copy_scanline_planar[i];
613     interpolate_scanline = self->interpolate_scanline_planar[i];
614 
615     gst_deinterlace_simple_method_deinterlace_frame_planar_plane (self,
616         outframe, &lg, cur_field_flags, i, copy_scanline, interpolate_scanline);
617   }
618 }
619 
620 static void
gst_deinterlace_simple_method_deinterlace_frame_nv12(GstDeinterlaceMethod * method,const GstDeinterlaceField * history,guint history_count,GstVideoFrame * outframe,gint cur_field_idx)621 gst_deinterlace_simple_method_deinterlace_frame_nv12 (GstDeinterlaceMethod *
622     method, const GstDeinterlaceField * history, guint history_count,
623     GstVideoFrame * outframe, gint cur_field_idx)
624 {
625   GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
626 #ifndef G_DISABLE_ASSERT
627   GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self);
628 #endif
629   guint cur_field_flags = history[cur_field_idx].flags;
630   LinesGetter lg = { history, history_count, cur_field_idx, };
631 
632   /* Y plane is at position 0 */
633   g_assert (self->interpolate_scanline_packed != NULL);
634   g_assert (self->copy_scanline_packed != NULL);
635   g_assert (self->interpolate_scanline_planar[0] != NULL);
636   g_assert (self->copy_scanline_planar[0] != NULL);
637   g_assert (dm_class->fields_required <= 5);
638 
639   /* Y plane first, then UV/VU plane */
640   gst_deinterlace_simple_method_deinterlace_frame_planar_plane (self,
641       outframe, &lg, cur_field_flags, 0,
642       self->copy_scanline_planar[0], self->interpolate_scanline_planar[0]);
643   gst_deinterlace_simple_method_deinterlace_frame_planar_plane (self,
644       outframe, &lg, cur_field_flags, 1,
645       self->copy_scanline_packed, self->interpolate_scanline_packed);
646 }
647 
648 static void
gst_deinterlace_simple_method_setup(GstDeinterlaceMethod * method,GstVideoInfo * vinfo)649 gst_deinterlace_simple_method_setup (GstDeinterlaceMethod * method,
650     GstVideoInfo * vinfo)
651 {
652   GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
653   GstDeinterlaceSimpleMethodClass *klass =
654       GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS (self);
655 
656   GST_DEINTERLACE_METHOD_CLASS
657       (gst_deinterlace_simple_method_parent_class)->setup (method, vinfo);
658 
659   self->interpolate_scanline_packed = NULL;
660   self->copy_scanline_packed = NULL;
661 
662   self->interpolate_scanline_planar[0] = NULL;
663   self->interpolate_scanline_planar[1] = NULL;
664   self->interpolate_scanline_planar[2] = NULL;
665   self->copy_scanline_planar[0] = NULL;
666   self->copy_scanline_planar[1] = NULL;
667   self->copy_scanline_planar[2] = NULL;
668 
669   if (GST_VIDEO_INFO_FORMAT (vinfo) == GST_VIDEO_FORMAT_UNKNOWN)
670     return;
671 
672   switch (GST_VIDEO_INFO_FORMAT (vinfo)) {
673     case GST_VIDEO_FORMAT_YUY2:
674       self->interpolate_scanline_packed = klass->interpolate_scanline_yuy2;
675       self->copy_scanline_packed = klass->copy_scanline_yuy2;
676       break;
677     case GST_VIDEO_FORMAT_YVYU:
678       self->interpolate_scanline_packed = klass->interpolate_scanline_yvyu;
679       self->copy_scanline_packed = klass->copy_scanline_yvyu;
680       break;
681     case GST_VIDEO_FORMAT_UYVY:
682       self->interpolate_scanline_packed = klass->interpolate_scanline_uyvy;
683       self->copy_scanline_packed = klass->copy_scanline_uyvy;
684       break;
685     case GST_VIDEO_FORMAT_AYUV:
686       self->interpolate_scanline_packed = klass->interpolate_scanline_ayuv;
687       self->copy_scanline_packed = klass->copy_scanline_ayuv;
688       break;
689     case GST_VIDEO_FORMAT_ARGB:
690     case GST_VIDEO_FORMAT_xRGB:
691       self->interpolate_scanline_packed = klass->interpolate_scanline_argb;
692       self->copy_scanline_packed = klass->copy_scanline_argb;
693       break;
694     case GST_VIDEO_FORMAT_ABGR:
695     case GST_VIDEO_FORMAT_xBGR:
696       self->interpolate_scanline_packed = klass->interpolate_scanline_abgr;
697       self->copy_scanline_packed = klass->copy_scanline_abgr;
698       break;
699     case GST_VIDEO_FORMAT_RGBA:
700     case GST_VIDEO_FORMAT_RGBx:
701       self->interpolate_scanline_packed = klass->interpolate_scanline_rgba;
702       self->copy_scanline_packed = klass->copy_scanline_rgba;
703       break;
704     case GST_VIDEO_FORMAT_BGRA:
705     case GST_VIDEO_FORMAT_BGRx:
706       self->interpolate_scanline_packed = klass->interpolate_scanline_bgra;
707       self->copy_scanline_packed = klass->copy_scanline_bgra;
708       break;
709     case GST_VIDEO_FORMAT_RGB:
710       self->interpolate_scanline_packed = klass->interpolate_scanline_rgb;
711       self->copy_scanline_packed = klass->copy_scanline_rgb;
712       break;
713     case GST_VIDEO_FORMAT_BGR:
714       self->interpolate_scanline_packed = klass->interpolate_scanline_bgr;
715       self->copy_scanline_packed = klass->copy_scanline_bgr;
716       break;
717     case GST_VIDEO_FORMAT_NV12:
718       self->interpolate_scanline_packed = klass->interpolate_scanline_nv12;
719       self->copy_scanline_packed = klass->copy_scanline_nv12;
720       self->interpolate_scanline_planar[0] =
721           klass->interpolate_scanline_planar_y;
722       self->copy_scanline_planar[0] = klass->copy_scanline_planar_y;
723       break;
724     case GST_VIDEO_FORMAT_NV21:
725       self->interpolate_scanline_packed = klass->interpolate_scanline_nv21;
726       self->copy_scanline_packed = klass->copy_scanline_nv21;
727       self->interpolate_scanline_planar[0] =
728           klass->interpolate_scanline_planar_y;
729       self->copy_scanline_planar[0] = klass->copy_scanline_planar_y;
730       break;
731     case GST_VIDEO_FORMAT_I420:
732     case GST_VIDEO_FORMAT_YV12:
733     case GST_VIDEO_FORMAT_Y444:
734     case GST_VIDEO_FORMAT_Y42B:
735     case GST_VIDEO_FORMAT_Y41B:
736       self->interpolate_scanline_planar[0] =
737           klass->interpolate_scanline_planar_y;
738       self->copy_scanline_planar[0] = klass->copy_scanline_planar_y;
739       self->interpolate_scanline_planar[1] =
740           klass->interpolate_scanline_planar_u;
741       self->copy_scanline_planar[1] = klass->copy_scanline_planar_u;
742       self->interpolate_scanline_planar[2] =
743           klass->interpolate_scanline_planar_v;
744       self->copy_scanline_planar[2] = klass->copy_scanline_planar_v;
745       break;
746     default:
747       break;
748   }
749 }
750 
751 static void
gst_deinterlace_simple_method_class_init(GstDeinterlaceSimpleMethodClass * klass)752 gst_deinterlace_simple_method_class_init (GstDeinterlaceSimpleMethodClass
753     * klass)
754 {
755   GstDeinterlaceMethodClass *dm_class = (GstDeinterlaceMethodClass *) klass;
756 
757   dm_class->deinterlace_frame_ayuv =
758       gst_deinterlace_simple_method_deinterlace_frame_packed;
759   dm_class->deinterlace_frame_yuy2 =
760       gst_deinterlace_simple_method_deinterlace_frame_packed;
761   dm_class->deinterlace_frame_yvyu =
762       gst_deinterlace_simple_method_deinterlace_frame_packed;
763   dm_class->deinterlace_frame_uyvy =
764       gst_deinterlace_simple_method_deinterlace_frame_packed;
765   dm_class->deinterlace_frame_argb =
766       gst_deinterlace_simple_method_deinterlace_frame_packed;
767   dm_class->deinterlace_frame_abgr =
768       gst_deinterlace_simple_method_deinterlace_frame_packed;
769   dm_class->deinterlace_frame_rgba =
770       gst_deinterlace_simple_method_deinterlace_frame_packed;
771   dm_class->deinterlace_frame_bgra =
772       gst_deinterlace_simple_method_deinterlace_frame_packed;
773   dm_class->deinterlace_frame_rgb =
774       gst_deinterlace_simple_method_deinterlace_frame_packed;
775   dm_class->deinterlace_frame_bgr =
776       gst_deinterlace_simple_method_deinterlace_frame_packed;
777   dm_class->deinterlace_frame_i420 =
778       gst_deinterlace_simple_method_deinterlace_frame_planar;
779   dm_class->deinterlace_frame_yv12 =
780       gst_deinterlace_simple_method_deinterlace_frame_planar;
781   dm_class->deinterlace_frame_y444 =
782       gst_deinterlace_simple_method_deinterlace_frame_planar;
783   dm_class->deinterlace_frame_y42b =
784       gst_deinterlace_simple_method_deinterlace_frame_planar;
785   dm_class->deinterlace_frame_y41b =
786       gst_deinterlace_simple_method_deinterlace_frame_planar;
787   dm_class->deinterlace_frame_nv12 =
788       gst_deinterlace_simple_method_deinterlace_frame_nv12;
789   dm_class->deinterlace_frame_nv21 =
790       gst_deinterlace_simple_method_deinterlace_frame_nv12;
791   dm_class->fields_required = 2;
792   dm_class->setup = gst_deinterlace_simple_method_setup;
793   dm_class->supported = gst_deinterlace_simple_method_supported;
794 
795   klass->interpolate_scanline_yuy2 =
796       gst_deinterlace_simple_method_interpolate_scanline_packed;
797   klass->copy_scanline_yuy2 =
798       gst_deinterlace_simple_method_copy_scanline_packed;
799   klass->interpolate_scanline_yvyu =
800       gst_deinterlace_simple_method_interpolate_scanline_packed;
801   klass->copy_scanline_yvyu =
802       gst_deinterlace_simple_method_copy_scanline_packed;
803   klass->interpolate_scanline_ayuv =
804       gst_deinterlace_simple_method_interpolate_scanline_packed;
805   klass->copy_scanline_ayuv =
806       gst_deinterlace_simple_method_copy_scanline_packed;
807   klass->interpolate_scanline_uyvy =
808       gst_deinterlace_simple_method_interpolate_scanline_packed;
809   klass->copy_scanline_uyvy =
810       gst_deinterlace_simple_method_copy_scanline_packed;
811   klass->interpolate_scanline_nv12 =
812       gst_deinterlace_simple_method_interpolate_scanline_packed;
813   klass->copy_scanline_nv12 =
814       gst_deinterlace_simple_method_copy_scanline_packed;
815 
816   klass->interpolate_scanline_argb =
817       gst_deinterlace_simple_method_interpolate_scanline_packed;
818   klass->copy_scanline_argb =
819       gst_deinterlace_simple_method_copy_scanline_packed;
820   klass->interpolate_scanline_abgr =
821       gst_deinterlace_simple_method_interpolate_scanline_packed;
822   klass->copy_scanline_abgr =
823       gst_deinterlace_simple_method_copy_scanline_packed;
824 
825   klass->interpolate_scanline_rgba =
826       gst_deinterlace_simple_method_interpolate_scanline_packed;
827   klass->copy_scanline_rgba =
828       gst_deinterlace_simple_method_copy_scanline_packed;
829   klass->interpolate_scanline_bgra =
830       gst_deinterlace_simple_method_interpolate_scanline_packed;
831   klass->copy_scanline_bgra =
832       gst_deinterlace_simple_method_copy_scanline_packed;
833   klass->interpolate_scanline_rgb =
834       gst_deinterlace_simple_method_interpolate_scanline_packed;
835   klass->copy_scanline_rgb = gst_deinterlace_simple_method_copy_scanline_packed;
836   klass->interpolate_scanline_bgr =
837       gst_deinterlace_simple_method_interpolate_scanline_packed;
838   klass->copy_scanline_bgr = gst_deinterlace_simple_method_copy_scanline_packed;
839 
840   klass->interpolate_scanline_planar_y =
841       gst_deinterlace_simple_method_interpolate_scanline_planar_y;
842   klass->copy_scanline_planar_y =
843       gst_deinterlace_simple_method_copy_scanline_planar_y;
844   klass->interpolate_scanline_planar_u =
845       gst_deinterlace_simple_method_interpolate_scanline_planar_u;
846   klass->copy_scanline_planar_u =
847       gst_deinterlace_simple_method_copy_scanline_planar_u;
848   klass->interpolate_scanline_planar_v =
849       gst_deinterlace_simple_method_interpolate_scanline_planar_v;
850   klass->copy_scanline_planar_v =
851       gst_deinterlace_simple_method_copy_scanline_planar_v;
852 }
853 
854 static void
gst_deinterlace_simple_method_init(GstDeinterlaceSimpleMethod * self)855 gst_deinterlace_simple_method_init (GstDeinterlaceSimpleMethod * self)
856 {
857 }
858