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     case GST_VIDEO_FORMAT_NV21:
273       return (klass->interpolate_scanline_nv21 != NULL
274           && klass->copy_scanline_nv21 != NULL);
275     case GST_VIDEO_FORMAT_I420:
276     case GST_VIDEO_FORMAT_YV12:
277     case GST_VIDEO_FORMAT_Y444:
278     case GST_VIDEO_FORMAT_Y42B:
279     case GST_VIDEO_FORMAT_Y41B:
280       return (klass->interpolate_scanline_planar_y != NULL
281           && klass->copy_scanline_planar_y != NULL &&
282           klass->interpolate_scanline_planar_u != NULL
283           && klass->copy_scanline_planar_u != NULL &&
284           klass->interpolate_scanline_planar_v != NULL
285           && klass->copy_scanline_planar_v != NULL);
286     default:
287       return FALSE;
288   }
289 }
290 
291 static void
gst_deinterlace_simple_method_interpolate_scanline_packed(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint stride)292     gst_deinterlace_simple_method_interpolate_scanline_packed
293     (GstDeinterlaceSimpleMethod * self, guint8 * out,
294     const GstDeinterlaceScanlineData * scanlines, guint stride)
295 {
296   memcpy (out, scanlines->m1, stride);
297 }
298 
299 static void
gst_deinterlace_simple_method_copy_scanline_packed(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint stride)300 gst_deinterlace_simple_method_copy_scanline_packed (GstDeinterlaceSimpleMethod *
301     self, guint8 * out, const GstDeinterlaceScanlineData * scanlines,
302     guint stride)
303 {
304   memcpy (out, scanlines->m0, stride);
305 }
306 
307 static void
gst_deinterlace_simple_method_deinterlace_frame_packed(GstDeinterlaceMethod * method,const GstDeinterlaceField * history,guint history_count,GstVideoFrame * outframe,gint cur_field_idx)308 gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod *
309     method, const GstDeinterlaceField * history, guint history_count,
310     GstVideoFrame * outframe, gint cur_field_idx)
311 {
312   GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
313 #ifndef G_DISABLE_ASSERT
314   GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self);
315 #endif
316   GstDeinterlaceScanlineData scanlines;
317   guint cur_field_flags;
318   gint i;
319   gint frame_height, frame_width;
320   GstVideoFrame *framep, *frame0, *frame1, *frame2;
321 
322   g_assert (self->interpolate_scanline_packed != NULL);
323   g_assert (self->copy_scanline_packed != NULL);
324 
325   frame_height = GST_VIDEO_FRAME_HEIGHT (outframe);
326   frame_width = GST_VIDEO_FRAME_PLANE_STRIDE (outframe, 0);
327 
328   frame0 = history[cur_field_idx].frame;
329   frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (frame0, 0));
330   cur_field_flags = history[cur_field_idx].flags;
331 
332   framep = (cur_field_idx > 0 ? history[cur_field_idx - 1].frame : NULL);
333   if (framep)
334     frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (framep, 0));
335 
336   g_assert (dm_class->fields_required <= 4);
337 
338   frame1 =
339       (cur_field_idx + 1 <
340       history_count ? history[cur_field_idx + 1].frame : NULL);
341   if (frame1)
342     frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (frame1, 0));
343 
344   frame2 =
345       (cur_field_idx + 2 <
346       history_count ? history[cur_field_idx + 2].frame : NULL);
347   if (frame2)
348     frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (frame2, 0));
349 
350 #define CLAMP_LOW(i) (((i)<0) ? (i+2) : (i))
351 #define CLAMP_HI(i) (((i)>=(frame_height)) ? (i-2) : (i))
352 #define LINE(x,i) (((guint8*)GST_VIDEO_FRAME_PLANE_DATA((x),0)) + CLAMP_HI(CLAMP_LOW(i)) * \
353     GST_VIDEO_FRAME_PLANE_STRIDE((x),0))
354 #define LINE2(x,i) ((x) ? LINE(x,i) : NULL)
355 
356   for (i = 0; i < frame_height; i++) {
357     memset (&scanlines, 0, sizeof (scanlines));
358     scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
359 
360     if (!((i & 1) ^ scanlines.bottom_field)) {
361       /* copying */
362       scanlines.tp = LINE2 (framep, i - 1);
363       scanlines.bp = LINE2 (framep, i + 1);
364 
365       scanlines.tt0 = LINE2 (frame0, (i - 2 >= 0) ? i - 2 : i);
366       scanlines.m0 = LINE2 (frame0, i);
367       scanlines.bb0 = LINE2 (frame0, (i + 2 < frame_height ? i + 2 : i));
368 
369       scanlines.t1 = LINE2 (frame1, i - 1);
370       scanlines.b1 = LINE2 (frame1, i + 1);
371 
372       scanlines.tt2 = LINE2 (frame2, (i - 2 >= 0) ? i - 2 : i);
373       scanlines.m2 = LINE2 (frame2, i);
374       scanlines.bb2 = LINE2 (frame2, (i + 2 < frame_height ? i + 2 : i));
375 
376       self->copy_scanline_packed (self, LINE (outframe, i), &scanlines,
377           frame_width);
378     } else {
379       /* interpolating */
380       scanlines.ttp = LINE2 (framep, (i - 2 >= 0) ? i - 2 : i);
381       scanlines.mp = LINE2 (framep, i);
382       scanlines.bbp = LINE2 (framep, (i + 2 < frame_height ? i + 2 : i));
383 
384       scanlines.t0 = LINE2 (frame0, i - 1);
385       scanlines.b0 = LINE2 (frame0, i + 1);
386 
387       scanlines.tt1 = LINE2 (frame1, (i - 2 >= 0) ? i - 2 : i);
388       scanlines.m1 = LINE2 (frame1, i);
389       scanlines.bb1 = LINE2 (frame1, (i + 2 < frame_height ? i + 2 : i));
390 
391       scanlines.t2 = LINE2 (frame2, i - 1);
392       scanlines.b2 = LINE2 (frame2, i + 1);
393 
394       self->interpolate_scanline_packed (self, LINE (outframe, i), &scanlines,
395           frame_width);
396     }
397 #undef LINE
398 #undef LINE2
399   }
400 }
401 
402 static void
gst_deinterlace_simple_method_interpolate_scanline_planar_y(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)403     gst_deinterlace_simple_method_interpolate_scanline_planar_y
404     (GstDeinterlaceSimpleMethod * self, guint8 * out,
405     const GstDeinterlaceScanlineData * scanlines, guint size)
406 {
407   memcpy (out, scanlines->m1, size);
408 }
409 
410 static void
gst_deinterlace_simple_method_copy_scanline_planar_y(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)411 gst_deinterlace_simple_method_copy_scanline_planar_y (GstDeinterlaceSimpleMethod
412     * self, guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint
413     size)
414 {
415   memcpy (out, scanlines->m0, size);
416 }
417 
418 static void
gst_deinterlace_simple_method_interpolate_scanline_planar_u(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)419     gst_deinterlace_simple_method_interpolate_scanline_planar_u
420     (GstDeinterlaceSimpleMethod * self, guint8 * out,
421     const GstDeinterlaceScanlineData * scanlines, guint size)
422 {
423   memcpy (out, scanlines->m1, size);
424 }
425 
426 static void
gst_deinterlace_simple_method_copy_scanline_planar_u(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)427 gst_deinterlace_simple_method_copy_scanline_planar_u (GstDeinterlaceSimpleMethod
428     * self, guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint
429     size)
430 {
431   memcpy (out, scanlines->m0, size);
432 }
433 
434 static void
gst_deinterlace_simple_method_interpolate_scanline_planar_v(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)435     gst_deinterlace_simple_method_interpolate_scanline_planar_v
436     (GstDeinterlaceSimpleMethod * self, guint8 * out,
437     const GstDeinterlaceScanlineData * scanlines, guint size)
438 {
439   memcpy (out, scanlines->m1, size);
440 }
441 
442 static void
gst_deinterlace_simple_method_copy_scanline_planar_v(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)443 gst_deinterlace_simple_method_copy_scanline_planar_v (GstDeinterlaceSimpleMethod
444     * self, guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint
445     size)
446 {
447   memcpy (out, scanlines->m0, size);
448 }
449 
450 static void
gst_deinterlace_simple_method_deinterlace_frame_planar_plane(GstDeinterlaceSimpleMethod * self,GstVideoFrame * dest,const GstVideoFrame * frame0,const GstVideoFrame * frame1,const GstVideoFrame * frame2,const GstVideoFrame * framep,guint cur_field_flags,gint plane,GstDeinterlaceSimpleMethodFunction copy_scanline,GstDeinterlaceSimpleMethodFunction interpolate_scanline)451     gst_deinterlace_simple_method_deinterlace_frame_planar_plane
452     (GstDeinterlaceSimpleMethod * self, GstVideoFrame * dest,
453     const GstVideoFrame * frame0, const GstVideoFrame * frame1,
454     const GstVideoFrame * frame2, const GstVideoFrame * framep,
455     guint cur_field_flags, gint plane,
456     GstDeinterlaceSimpleMethodFunction copy_scanline,
457     GstDeinterlaceSimpleMethodFunction interpolate_scanline)
458 {
459   GstDeinterlaceScanlineData scanlines;
460   gint i;
461   gint frame_height, frame_width;
462 
463   frame_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, plane);
464   frame_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, plane) *
465       GST_VIDEO_FRAME_COMP_PSTRIDE (dest, plane);
466 
467   g_assert (interpolate_scanline != NULL);
468   g_assert (copy_scanline != NULL);
469 
470 #define LINE(x,i) (((guint8*)GST_VIDEO_FRAME_PLANE_DATA((x),plane)) + CLAMP_HI(CLAMP_LOW(i)) * \
471     GST_VIDEO_FRAME_PLANE_STRIDE((x),plane))
472 #define LINE2(x,i) ((x) ? LINE(x,i) : NULL)
473 
474   for (i = 0; i < frame_height; i++) {
475     memset (&scanlines, 0, sizeof (scanlines));
476     scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
477 
478     if (!((i & 1) ^ scanlines.bottom_field)) {
479       /* copying */
480       scanlines.tp = LINE2 (framep, i - 1);
481       scanlines.bp = LINE2 (framep, i + 1);
482 
483       scanlines.tt0 = LINE2 (frame0, (i - 2 >= 0) ? i - 2 : i);
484       scanlines.m0 = LINE2 (frame0, i);
485       scanlines.bb0 = LINE2 (frame0, (i + 2 < frame_height ? i + 2 : i));
486 
487       scanlines.t1 = LINE2 (frame1, i - 1);
488       scanlines.b1 = LINE2 (frame1, i + 1);
489 
490       scanlines.tt2 = LINE2 (frame2, (i - 2 >= 0) ? i - 2 : i);
491       scanlines.m2 = LINE2 (frame2, i);
492       scanlines.bb2 = LINE2 (frame2, (i + 2 < frame_height ? i + 2 : i));
493 
494       copy_scanline (self, LINE (dest, i), &scanlines, frame_width);
495     } else {
496       /* interpolating */
497       scanlines.ttp = LINE2 (framep, (i - 2 >= 0) ? i - 2 : i);
498       scanlines.mp = LINE2 (framep, i);
499       scanlines.bbp = LINE2 (framep, (i + 2 < frame_height ? i + 2 : i));
500 
501       scanlines.t0 = LINE2 (frame0, i - 1);
502       scanlines.b0 = LINE2 (frame0, i + 1);
503 
504       scanlines.tt1 = LINE2 (frame1, (i - 2 >= 0) ? i - 2 : i);
505       scanlines.m1 = LINE2 (frame1, i);
506       scanlines.bb1 = LINE2 (frame1, (i + 2 < frame_height ? i + 2 : i));
507 
508       scanlines.t2 = LINE2 (frame2, i - 1);
509       scanlines.b2 = LINE2 (frame2, i + 1);
510 
511       interpolate_scanline (self, LINE (dest, i), &scanlines, frame_width);
512     }
513 #undef LINE
514 #undef LINE2
515   }
516 }
517 
518 static void
gst_deinterlace_simple_method_deinterlace_frame_planar(GstDeinterlaceMethod * method,const GstDeinterlaceField * history,guint history_count,GstVideoFrame * outframe,gint cur_field_idx)519 gst_deinterlace_simple_method_deinterlace_frame_planar (GstDeinterlaceMethod *
520     method, const GstDeinterlaceField * history, guint history_count,
521     GstVideoFrame * outframe, gint cur_field_idx)
522 {
523   GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
524 #ifndef G_DISABLE_ASSERT
525   GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self);
526 #endif
527   const GstVideoFrame *frame0, *frame1, *frame2, *framep;
528   guint cur_field_flags = history[cur_field_idx].flags;
529   gint i;
530   GstDeinterlaceSimpleMethodFunction copy_scanline;
531   GstDeinterlaceSimpleMethodFunction interpolate_scanline;
532 
533   g_assert (self->interpolate_scanline_planar[0] != NULL);
534   g_assert (self->interpolate_scanline_planar[1] != NULL);
535   g_assert (self->interpolate_scanline_planar[2] != NULL);
536   g_assert (self->copy_scanline_planar[0] != NULL);
537   g_assert (self->copy_scanline_planar[1] != NULL);
538   g_assert (self->copy_scanline_planar[2] != NULL);
539 
540   for (i = 0; i < 3; i++) {
541     copy_scanline = self->copy_scanline_planar[i];
542     interpolate_scanline = self->interpolate_scanline_planar[i];
543 
544     framep = (cur_field_idx > 0 ? history[cur_field_idx - 1].frame : NULL);
545 
546     frame0 = history[cur_field_idx].frame;
547 
548     g_assert (dm_class->fields_required <= 4);
549 
550     frame1 =
551         (cur_field_idx + 1 <
552         history_count ? history[cur_field_idx + 1].frame : NULL);
553     frame2 =
554         (cur_field_idx + 2 <
555         history_count ? history[cur_field_idx + 2].frame : NULL);
556 
557     gst_deinterlace_simple_method_deinterlace_frame_planar_plane (self,
558         outframe, frame0, frame1, frame2, framep, cur_field_flags, i,
559         copy_scanline, interpolate_scanline);
560   }
561 }
562 
563 static void
gst_deinterlace_simple_method_deinterlace_frame_nv12(GstDeinterlaceMethod * method,const GstDeinterlaceField * history,guint history_count,GstVideoFrame * outframe,gint cur_field_idx)564 gst_deinterlace_simple_method_deinterlace_frame_nv12 (GstDeinterlaceMethod *
565     method, const GstDeinterlaceField * history, guint history_count,
566     GstVideoFrame * outframe, gint cur_field_idx)
567 {
568   GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
569 #ifndef G_DISABLE_ASSERT
570   GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self);
571 #endif
572   const GstVideoFrame *frame0, *frame1, *frame2, *framep;
573   guint cur_field_flags = history[cur_field_idx].flags;
574   gint i;
575 
576   g_assert (self->interpolate_scanline_packed != NULL);
577   g_assert (self->copy_scanline_packed != NULL);
578 
579   for (i = 0; i < 2; i++) {
580     framep = (cur_field_idx > 0 ? history[cur_field_idx - 1].frame : NULL);
581 
582     frame0 = history[cur_field_idx].frame;
583 
584     g_assert (dm_class->fields_required <= 4);
585 
586     frame1 =
587         (cur_field_idx + 1 <
588         history_count ? history[cur_field_idx + 1].frame : NULL);
589     frame2 =
590         (cur_field_idx + 2 <
591         history_count ? history[cur_field_idx + 2].frame : NULL);
592 
593     gst_deinterlace_simple_method_deinterlace_frame_planar_plane (self,
594         outframe, frame0, frame1, frame2, framep, cur_field_flags, i,
595         self->copy_scanline_packed, self->interpolate_scanline_packed);
596   }
597 }
598 
599 static void
gst_deinterlace_simple_method_setup(GstDeinterlaceMethod * method,GstVideoInfo * vinfo)600 gst_deinterlace_simple_method_setup (GstDeinterlaceMethod * method,
601     GstVideoInfo * vinfo)
602 {
603   GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
604   GstDeinterlaceSimpleMethodClass *klass =
605       GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS (self);
606 
607   GST_DEINTERLACE_METHOD_CLASS
608       (gst_deinterlace_simple_method_parent_class)->setup (method, vinfo);
609 
610   self->interpolate_scanline_packed = NULL;
611   self->copy_scanline_packed = NULL;
612 
613   self->interpolate_scanline_planar[0] = NULL;
614   self->interpolate_scanline_planar[1] = NULL;
615   self->interpolate_scanline_planar[2] = NULL;
616   self->copy_scanline_planar[0] = NULL;
617   self->copy_scanline_planar[1] = NULL;
618   self->copy_scanline_planar[2] = NULL;
619 
620   if (GST_VIDEO_INFO_FORMAT (vinfo) == GST_VIDEO_FORMAT_UNKNOWN)
621     return;
622 
623   switch (GST_VIDEO_INFO_FORMAT (vinfo)) {
624     case GST_VIDEO_FORMAT_YUY2:
625       self->interpolate_scanline_packed = klass->interpolate_scanline_yuy2;
626       self->copy_scanline_packed = klass->copy_scanline_yuy2;
627       break;
628     case GST_VIDEO_FORMAT_YVYU:
629       self->interpolate_scanline_packed = klass->interpolate_scanline_yvyu;
630       self->copy_scanline_packed = klass->copy_scanline_yvyu;
631       break;
632     case GST_VIDEO_FORMAT_UYVY:
633       self->interpolate_scanline_packed = klass->interpolate_scanline_uyvy;
634       self->copy_scanline_packed = klass->copy_scanline_uyvy;
635       break;
636     case GST_VIDEO_FORMAT_AYUV:
637       self->interpolate_scanline_packed = klass->interpolate_scanline_ayuv;
638       self->copy_scanline_packed = klass->copy_scanline_ayuv;
639       break;
640     case GST_VIDEO_FORMAT_ARGB:
641     case GST_VIDEO_FORMAT_xRGB:
642       self->interpolate_scanline_packed = klass->interpolate_scanline_argb;
643       self->copy_scanline_packed = klass->copy_scanline_argb;
644       break;
645     case GST_VIDEO_FORMAT_ABGR:
646     case GST_VIDEO_FORMAT_xBGR:
647       self->interpolate_scanline_packed = klass->interpolate_scanline_abgr;
648       self->copy_scanline_packed = klass->copy_scanline_abgr;
649       break;
650     case GST_VIDEO_FORMAT_RGBA:
651     case GST_VIDEO_FORMAT_RGBx:
652       self->interpolate_scanline_packed = klass->interpolate_scanline_rgba;
653       self->copy_scanline_packed = klass->copy_scanline_rgba;
654       break;
655     case GST_VIDEO_FORMAT_BGRA:
656     case GST_VIDEO_FORMAT_BGRx:
657       self->interpolate_scanline_packed = klass->interpolate_scanline_bgra;
658       self->copy_scanline_packed = klass->copy_scanline_bgra;
659       break;
660     case GST_VIDEO_FORMAT_RGB:
661       self->interpolate_scanline_packed = klass->interpolate_scanline_rgb;
662       self->copy_scanline_packed = klass->copy_scanline_rgb;
663       break;
664     case GST_VIDEO_FORMAT_BGR:
665       self->interpolate_scanline_packed = klass->interpolate_scanline_bgr;
666       self->copy_scanline_packed = klass->copy_scanline_bgr;
667       break;
668     case GST_VIDEO_FORMAT_NV12:
669       self->interpolate_scanline_packed = klass->interpolate_scanline_nv12;
670       self->copy_scanline_packed = klass->copy_scanline_nv12;
671       break;
672     case GST_VIDEO_FORMAT_NV21:
673       self->interpolate_scanline_packed = klass->interpolate_scanline_nv21;
674       self->copy_scanline_packed = klass->copy_scanline_nv21;
675       break;
676     case GST_VIDEO_FORMAT_I420:
677     case GST_VIDEO_FORMAT_YV12:
678     case GST_VIDEO_FORMAT_Y444:
679     case GST_VIDEO_FORMAT_Y42B:
680     case GST_VIDEO_FORMAT_Y41B:
681       self->interpolate_scanline_planar[0] =
682           klass->interpolate_scanline_planar_y;
683       self->copy_scanline_planar[0] = klass->copy_scanline_planar_y;
684       self->interpolate_scanline_planar[1] =
685           klass->interpolate_scanline_planar_u;
686       self->copy_scanline_planar[1] = klass->copy_scanline_planar_u;
687       self->interpolate_scanline_planar[2] =
688           klass->interpolate_scanline_planar_v;
689       self->copy_scanline_planar[2] = klass->copy_scanline_planar_v;
690       break;
691     default:
692       break;
693   }
694 }
695 
696 static void
gst_deinterlace_simple_method_class_init(GstDeinterlaceSimpleMethodClass * klass)697 gst_deinterlace_simple_method_class_init (GstDeinterlaceSimpleMethodClass
698     * klass)
699 {
700   GstDeinterlaceMethodClass *dm_class = (GstDeinterlaceMethodClass *) klass;
701 
702   dm_class->deinterlace_frame_ayuv =
703       gst_deinterlace_simple_method_deinterlace_frame_packed;
704   dm_class->deinterlace_frame_yuy2 =
705       gst_deinterlace_simple_method_deinterlace_frame_packed;
706   dm_class->deinterlace_frame_yvyu =
707       gst_deinterlace_simple_method_deinterlace_frame_packed;
708   dm_class->deinterlace_frame_uyvy =
709       gst_deinterlace_simple_method_deinterlace_frame_packed;
710   dm_class->deinterlace_frame_argb =
711       gst_deinterlace_simple_method_deinterlace_frame_packed;
712   dm_class->deinterlace_frame_abgr =
713       gst_deinterlace_simple_method_deinterlace_frame_packed;
714   dm_class->deinterlace_frame_rgba =
715       gst_deinterlace_simple_method_deinterlace_frame_packed;
716   dm_class->deinterlace_frame_bgra =
717       gst_deinterlace_simple_method_deinterlace_frame_packed;
718   dm_class->deinterlace_frame_rgb =
719       gst_deinterlace_simple_method_deinterlace_frame_packed;
720   dm_class->deinterlace_frame_bgr =
721       gst_deinterlace_simple_method_deinterlace_frame_packed;
722   dm_class->deinterlace_frame_i420 =
723       gst_deinterlace_simple_method_deinterlace_frame_planar;
724   dm_class->deinterlace_frame_yv12 =
725       gst_deinterlace_simple_method_deinterlace_frame_planar;
726   dm_class->deinterlace_frame_y444 =
727       gst_deinterlace_simple_method_deinterlace_frame_planar;
728   dm_class->deinterlace_frame_y42b =
729       gst_deinterlace_simple_method_deinterlace_frame_planar;
730   dm_class->deinterlace_frame_y41b =
731       gst_deinterlace_simple_method_deinterlace_frame_planar;
732   dm_class->deinterlace_frame_nv12 =
733       gst_deinterlace_simple_method_deinterlace_frame_nv12;
734   dm_class->deinterlace_frame_nv21 =
735       gst_deinterlace_simple_method_deinterlace_frame_nv12;
736   dm_class->fields_required = 2;
737   dm_class->setup = gst_deinterlace_simple_method_setup;
738   dm_class->supported = gst_deinterlace_simple_method_supported;
739 
740   klass->interpolate_scanline_yuy2 =
741       gst_deinterlace_simple_method_interpolate_scanline_packed;
742   klass->copy_scanline_yuy2 =
743       gst_deinterlace_simple_method_copy_scanline_packed;
744   klass->interpolate_scanline_yvyu =
745       gst_deinterlace_simple_method_interpolate_scanline_packed;
746   klass->copy_scanline_yvyu =
747       gst_deinterlace_simple_method_copy_scanline_packed;
748   klass->interpolate_scanline_ayuv =
749       gst_deinterlace_simple_method_interpolate_scanline_packed;
750   klass->copy_scanline_ayuv =
751       gst_deinterlace_simple_method_copy_scanline_packed;
752   klass->interpolate_scanline_uyvy =
753       gst_deinterlace_simple_method_interpolate_scanline_packed;
754   klass->copy_scanline_uyvy =
755       gst_deinterlace_simple_method_copy_scanline_packed;
756   klass->interpolate_scanline_nv12 =
757       gst_deinterlace_simple_method_interpolate_scanline_packed;
758   klass->copy_scanline_nv12 =
759       gst_deinterlace_simple_method_copy_scanline_packed;
760 
761   klass->interpolate_scanline_argb =
762       gst_deinterlace_simple_method_interpolate_scanline_packed;
763   klass->copy_scanline_argb =
764       gst_deinterlace_simple_method_copy_scanline_packed;
765   klass->interpolate_scanline_abgr =
766       gst_deinterlace_simple_method_interpolate_scanline_packed;
767   klass->copy_scanline_abgr =
768       gst_deinterlace_simple_method_copy_scanline_packed;
769 
770   klass->interpolate_scanline_rgba =
771       gst_deinterlace_simple_method_interpolate_scanline_packed;
772   klass->copy_scanline_rgba =
773       gst_deinterlace_simple_method_copy_scanline_packed;
774   klass->interpolate_scanline_bgra =
775       gst_deinterlace_simple_method_interpolate_scanline_packed;
776   klass->copy_scanline_bgra =
777       gst_deinterlace_simple_method_copy_scanline_packed;
778   klass->interpolate_scanline_rgb =
779       gst_deinterlace_simple_method_interpolate_scanline_packed;
780   klass->copy_scanline_rgb = gst_deinterlace_simple_method_copy_scanline_packed;
781   klass->interpolate_scanline_bgr =
782       gst_deinterlace_simple_method_interpolate_scanline_packed;
783   klass->copy_scanline_bgr = gst_deinterlace_simple_method_copy_scanline_packed;
784 
785   klass->interpolate_scanline_planar_y =
786       gst_deinterlace_simple_method_interpolate_scanline_planar_y;
787   klass->copy_scanline_planar_y =
788       gst_deinterlace_simple_method_copy_scanline_planar_y;
789   klass->interpolate_scanline_planar_u =
790       gst_deinterlace_simple_method_interpolate_scanline_planar_u;
791   klass->copy_scanline_planar_u =
792       gst_deinterlace_simple_method_copy_scanline_planar_u;
793   klass->interpolate_scanline_planar_v =
794       gst_deinterlace_simple_method_interpolate_scanline_planar_v;
795   klass->copy_scanline_planar_v =
796       gst_deinterlace_simple_method_copy_scanline_planar_v;
797 }
798 
799 static void
gst_deinterlace_simple_method_init(GstDeinterlaceSimpleMethod * self)800 gst_deinterlace_simple_method_init (GstDeinterlaceSimpleMethod * self)
801 {
802 }
803