1 /* GStreamer
2 * Copyright (C) 2013 Wim Taymans <wim.taymans@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <string.h>
25 #include <stdio.h>
26
27 #include "video-orc.h"
28 #include "video-format.h"
29
30
31 /**
32 * SECTION:gstvideochroma
33 * @title: GstVideoChromaResample
34 * @short_description: Functions and utility object for operating on chroma video planes
35 *
36 * The functions gst_video_chroma_from_string() and gst_video_chroma_to_string() convert
37 * between #GstVideoChromaSite and string descriptions.
38 *
39 * #GstVideoChromaResample is a utility object for resampling chroma planes
40 * and converting between different chroma sampling sitings.
41 *
42 */
43
44 #ifndef GST_DISABLE_GST_DEBUG
45 #define GST_CAT_DEFAULT ensure_debug_category()
46 static GstDebugCategory *
ensure_debug_category(void)47 ensure_debug_category (void)
48 {
49 static gsize cat_gonce = 0;
50
51 if (g_once_init_enter (&cat_gonce)) {
52 gsize cat_done;
53
54 cat_done = (gsize) _gst_debug_category_new ("video-chroma", 0,
55 "video-chroma object");
56
57 g_once_init_leave (&cat_gonce, cat_done);
58 }
59
60 return (GstDebugCategory *) cat_gonce;
61 }
62 #else
63 #define ensure_debug_category() /* NOOP */
64 #endif /* GST_DISABLE_GST_DEBUG */
65
66 typedef struct
67 {
68 const gchar *name;
69 GstVideoChromaSite site;
70 } ChromaSiteInfo;
71
72 static const ChromaSiteInfo chromasite[] = {
73 {"jpeg", GST_VIDEO_CHROMA_SITE_JPEG},
74 {"mpeg2", GST_VIDEO_CHROMA_SITE_MPEG2},
75 {"dv", GST_VIDEO_CHROMA_SITE_DV}
76 };
77
78 /**
79 * gst_video_chroma_from_string:
80 * @s: a chromasite string
81 *
82 * Convert @s to a #GstVideoChromaSite
83 *
84 * Returns: a #GstVideoChromaSite or %GST_VIDEO_CHROMA_SITE_UNKNOWN when @s does
85 * not contain a valid chroma description.
86 */
87 GstVideoChromaSite
gst_video_chroma_from_string(const gchar * s)88 gst_video_chroma_from_string (const gchar * s)
89 {
90 gint i;
91 for (i = 0; i < G_N_ELEMENTS (chromasite); i++) {
92 if (g_str_equal (chromasite[i].name, s))
93 return chromasite[i].site;
94 }
95 return GST_VIDEO_CHROMA_SITE_UNKNOWN;
96 }
97
98 /**
99 * gst_video_chroma_to_string:
100 * @site: a #GstVideoChromaSite
101 *
102 * Converts @site to its string representation.
103 *
104 * Returns: a string describing @site.
105 */
106 const gchar *
gst_video_chroma_to_string(GstVideoChromaSite site)107 gst_video_chroma_to_string (GstVideoChromaSite site)
108 {
109 gint i;
110 for (i = 0; i < G_N_ELEMENTS (chromasite); i++) {
111 if (chromasite[i].site == site)
112 return chromasite[i].name;
113 }
114 return NULL;
115 }
116
117 struct _GstVideoChromaResample
118 {
119 GstVideoChromaMethod method;
120 GstVideoChromaSite site;
121 GstVideoChromaFlags flags;
122 GstVideoFormat format;
123 gint h_factor, v_factor;
124 guint n_lines;
125 gint offset;
126 void (*h_resample) (GstVideoChromaResample * resample, gpointer pixels,
127 gint width);
128 void (*v_resample) (GstVideoChromaResample * resample, gpointer lines[],
129 gint width);
130 };
131
132 #define PR(i) (p[2 + 4 * (i)])
133 #define PB(i) (p[3 + 4 * (i)])
134
135 #define PR0(i) (l0[2 + 4 * (i)])
136 #define PR1(i) (l1[2 + 4 * (i)])
137 #define PR2(i) (l2[2 + 4 * (i)])
138 #define PR3(i) (l3[2 + 4 * (i)])
139 #define PB0(i) (l0[3 + 4 * (i)])
140 #define PB1(i) (l1[3 + 4 * (i)])
141 #define PB2(i) (l2[3 + 4 * (i)])
142 #define PB3(i) (l3[3 + 4 * (i)])
143
144 #define FILT_1_1(a,b) ((a) + (b) + 1) >> 1
145 #define FILT_1_3_3_1(a,b,c,d) ((a) + 3*((b)+(c)) + (d) + 4) >> 3
146
147 #define FILT_3_1(a,b) (3*(a) + (b) + 2) >> 2
148 #define FILT_1_3(a,b) ((a) + 3*(b) + 2) >> 2
149 #define FILT_1_2_1(a,b,c) ((a) + 2*(b) + (c) + 2) >> 2
150
151 #define FILT_7_1(a,b) (7*(a) + 1*(b) + 4) >> 3
152 #define FILT_1_7(a,b) (1*(a) + 7*(b) + 4) >> 3
153
154 #define FILT_5_3(a,b) (5*(a) + 3*(b) + 4) >> 3
155 #define FILT_3_5(a,b) (3*(a) + 5*(b) + 4) >> 3
156
157 #define FILT_10_3_2_1(a,b,c,d) (10*(a) + 3*(b) + 2*(c) + (d) + 8) >> 16
158 #define FILT_1_2_3_10(a,b,c,d) ((a) + 2*(b) + 3*(c) + 10*(d) + 8) >> 16
159 #define FILT_1_2_3_4_3_2_1(a,b,c,d,e,f,g) ((a) + 2*((b)+(f)) + 3*((c)+(e)) + 4*(d) + (g) + 8) >> 16
160
161 /* 2x horizontal upsampling without cositing
162 *
163 * +---------- a
164 * | +------ (3*a + b + 2) >> 2
165 * | | +---- ( a + 3*b + 2) >> 2
166 * v v v
167 * O-O-O-O-
168 * x x
169 * a b
170 */
171 #define MAKE_UPSAMPLE_H2(name,type) \
172 static void \
173 video_chroma_up_h2_##name (GstVideoChromaResample *resample, \
174 gpointer pixels, gint width) \
175 { \
176 type *p = pixels; \
177 gint i; \
178 type tr0, tr1; \
179 type tb0, tb1; \
180 \
181 tr1 = PR(0); \
182 tb1 = PB(0); \
183 for (i = 1; i < width - 1; i += 2) { \
184 tr0 = tr1, tr1 = PR(i+1); \
185 tb0 = tb1, tb1 = PB(i+1); \
186 \
187 PR(i) = FILT_3_1 (tr0, tr1); \
188 PB(i) = FILT_3_1 (tb0, tb1); \
189 PR(i+1) = FILT_1_3 (tr0, tr1); \
190 PB(i+1) = FILT_1_3 (tb0, tb1); \
191 } \
192 }
193
194 /* 2x vertical upsampling without cositing
195 *
196 * O--O--O- <---- a
197 * a x x x
198 * O--O--O- <---- (3*a + b + 2) >> 2
199 * O--O--O- <-----( a + 3*b + 2) >> 2
200 * b x x x
201 * O--O--O- <---- b
202 */
203 #define MAKE_UPSAMPLE_V2(name,type) \
204 static void \
205 video_chroma_up_v2_##name (GstVideoChromaResample *resample, \
206 gpointer lines[], gint width) \
207 { \
208 type *l0 = lines[0]; \
209 type *l1 = lines[1]; \
210 \
211 if (resample->h_resample) { \
212 resample->h_resample (resample, l0, width); \
213 if (l0 != l1) \
214 resample->h_resample (resample, l1, width); \
215 } \
216 if (l0 != l1) { \
217 type *d0 = l0; \
218 type *d1 = l1; \
219 video_orc_chroma_up_v2_##name (d0, d1, l0, l1, width); \
220 } \
221 }
222 /* 2x vertical upsampling interlaced without cositing
223 *
224 * even odd
225 *
226 * O--O--O--------------- <--- a
227 * a x x x
228 * --------------O--O--O- <--- c
229 * O--O--O--------------- <--- (5*a + 3*b + 4) >> 3
230 * c x x x
231 * --------------O--O--O- <--- (7*c + d + 4) >> 3
232 * O--O--O--------------- <--- ( a + 7*b + 4) >> 3
233 * b x x x
234 * --------------O--O--O- <--- (3*c + 5*d + 4) >> 3
235 * O--O--O---------------
236 * d x x x
237 * --------------O--O--O-
238 */
239 #define MAKE_UPSAMPLE_VI2(name,type) \
240 static void \
241 video_chroma_up_vi2_##name (GstVideoChromaResample *resample, \
242 gpointer lines[], gint width) \
243 { \
244 gint i; \
245 type *l0 = lines[0]; \
246 type *l1 = lines[1]; \
247 type *l2 = lines[2]; \
248 type *l3 = lines[3]; \
249 type tr0, tr1, tr2, tr3; \
250 type tb0, tb1, tb2, tb3; \
251 \
252 if (resample->h_resample) { \
253 if (l0 != l1) { \
254 resample->h_resample (resample, l0, width); \
255 resample->h_resample (resample, l1, width); \
256 } \
257 if (l2 != l3) { \
258 resample->h_resample (resample, l2, width); \
259 resample->h_resample (resample, l3, width); \
260 } \
261 } \
262 if (l0 != l1 && l2 != l3) { \
263 for (i = 0; i < width; i++) { \
264 tr0 = PR0(i), tr2 = PR2(i); \
265 tb0 = PB0(i), tb2 = PB2(i); \
266 tr1 = PR1(i), tr3 = PR3(i); \
267 tb1 = PB1(i), tb3 = PB3(i); \
268 \
269 PR0(i) = FILT_5_3 (tr0, tr2); \
270 PB0(i) = FILT_5_3 (tb0, tb2); \
271 PR1(i) = FILT_7_1 (tr1, tr3); \
272 PB1(i) = FILT_7_1 (tb1, tb3); \
273 PR2(i) = FILT_1_7 (tr0, tr2); \
274 PB2(i) = FILT_1_7 (tb0, tb2); \
275 PR3(i) = FILT_3_5 (tr1, tr3); \
276 PB3(i) = FILT_3_5 (tb1, tb3); \
277 } \
278 } \
279 }
280
281 /* 2x horizontal downsampling without cositing
282 *
283 * +------ (a + b+ 1) >> 1
284 * |
285 * v
286 * -O---O--
287 * x x x x
288 * a b c d
289 */
290 #define MAKE_DOWNSAMPLE_H2_ORC(name,type) \
291 static void \
292 video_chroma_down_h2_##name (GstVideoChromaResample *resample, \
293 gpointer pixels, gint width) \
294 { \
295 type *p = pixels; \
296 type *d = p; \
297 \
298 video_orc_chroma_down_h2_##name (d, p, width / 2); \
299 }
300
301 #define MAKE_DOWNSAMPLE_H2(name,type) \
302 static void \
303 video_chroma_down_h2_##name (GstVideoChromaResample *resample, \
304 gpointer pixels, gint width) \
305 { \
306 type *p = pixels; \
307 gint i; \
308 \
309 for (i = 0; i < width - 1; i += 2) { \
310 type tr0 = PR(i), tr1 = PR(i+1); \
311 type tb0 = PB(i), tb1 = PB(i+1); \
312 \
313 PR(i) = FILT_1_1 (tr0, tr1); \
314 PB(i) = FILT_1_1 (tb0, tb1); \
315 } \
316 }
317 /* 2x vertical downsampling without cositing
318 *
319 * a x--x--x-
320 * O O O <---- (a + b + 1) >> 1
321 * b x--x--x-
322 * c x--x--x-
323 * O O O
324 * d x--x--x-
325 */
326 #define MAKE_DOWNSAMPLE_V2(name,type) \
327 static void \
328 video_chroma_down_v2_##name (GstVideoChromaResample *resample, \
329 gpointer lines[], gint width) \
330 { \
331 type *l0 = lines[0]; \
332 type *l1 = lines[1]; \
333 \
334 if (l0 != l1) { \
335 type *d0 = l0; \
336 video_orc_chroma_down_v2_##name (d0, l0, l1, width); \
337 } \
338 \
339 if (resample->h_resample) \
340 resample->h_resample (resample, l0, width); \
341 }
342 /* 2x vertical downsampling interlaced without cositing
343 *
344 * even odd
345 *
346 * a x--x--x---------------
347 * O O O <---
348 * b --------------x--x--x-
349 * c x--x--x---------------
350 * O O O <---
351 * d --------------x--x--x-
352 */
353 #define MAKE_DOWNSAMPLE_VI2(name,type) \
354 static void \
355 video_chroma_down_vi2_##name (GstVideoChromaResample *resample, \
356 gpointer lines[], gint width) \
357 { \
358 /* FIXME */ \
359 if (resample->h_resample) \
360 resample->h_resample (resample, lines[0], width); \
361 }
362
363 MAKE_UPSAMPLE_H2 (u16, guint16);
364 MAKE_UPSAMPLE_H2 (u8, guint8);
365 MAKE_UPSAMPLE_V2 (u16, guint16);
366 MAKE_UPSAMPLE_V2 (u8, guint8);
367 MAKE_UPSAMPLE_VI2 (u16, guint16);
368 MAKE_UPSAMPLE_VI2 (u8, guint8);
369 MAKE_DOWNSAMPLE_H2 (u16, guint16);
370 MAKE_DOWNSAMPLE_H2_ORC (u8, guint8);
371 MAKE_DOWNSAMPLE_V2 (u16, guint16);
372 MAKE_DOWNSAMPLE_V2 (u8, guint8);
373 MAKE_DOWNSAMPLE_VI2 (u16, guint16);
374 MAKE_DOWNSAMPLE_VI2 (u8, guint8);
375
376 /* 4x horizontal upsampling without cositing
377 *
378 * +---------- (7*a + b + 4) >> 3
379 * | +-------- (5*a + 3*b + 4) >> 3
380 * a a | | +------ (3*a + 5*b + 4) >> 3
381 * | | | | | +---- ( a + 7*b + 4) >> 3
382 * v v v v v v
383 * O-O-O-O-O-O-O-O-
384 * x x
385 * a b
386 */
387 #define MAKE_UPSAMPLE_H4(name,type) \
388 static void \
389 video_chroma_up_h4_##name (GstVideoChromaResample *resample, \
390 gpointer pixels, gint width) \
391 { \
392 type *p = pixels; \
393 gint i; \
394 type tr0, tr1; \
395 type tb0, tb1; \
396 \
397 tr1 = PR(0); \
398 tb1 = PB(0); \
399 for (i = 2; i < width - 3; i += 4) { \
400 tr0 = tr1, tr1 = PR(i+2); \
401 tb0 = tb1, tb1 = PB(i+2); \
402 \
403 PR(i) = FILT_7_1 (tr0, tr1); \
404 PB(i) = FILT_7_1 (tb0, tb1); \
405 PR(i+1) = FILT_5_3 (tr0, tr1); \
406 PB(i+1) = FILT_5_3 (tb0, tb1); \
407 PR(i+2) = FILT_3_5 (tr0, tr1); \
408 PB(i+2) = FILT_3_5 (tb0, tb1); \
409 PR(i+3) = FILT_1_7 (tr0, tr1); \
410 PB(i+3) = FILT_1_7 (tb0, tb1); \
411 } \
412 }
413
414 /* 4x vertical upsampling without cositing
415 *
416 * O--O--O- <---- a
417 * O--O--O- <---- a
418 * a x x x
419 * O--O--O- <---- (7*a + b + 4) >> 3
420 * O--O--O- <---- (5*a + 3*b + 4) >> 3
421 * O--O--O- <---- (3*a + 5*b + 4) >> 3
422 * O--O--O- <-----( a + 7*b + 4) >> 3
423 * b x x x
424 * O--O--O-
425 * O--O--O-
426 */
427 #define MAKE_UPSAMPLE_V4(name,type) \
428 static void \
429 video_chroma_up_v4_##name (GstVideoChromaResample *resample, \
430 gpointer lines[], gint width) \
431 { \
432 gint i; \
433 type *l0 = lines[0]; \
434 type *l1 = lines[1]; \
435 type *l2 = lines[2]; \
436 type *l3 = lines[3]; \
437 type tr0, tr1; \
438 type tb0, tb1; \
439 \
440 if (resample->h_resample) { \
441 if (l0 != l1) { \
442 resample->h_resample (resample, l0, width); \
443 resample->h_resample (resample, l1, width); \
444 } \
445 if (l2 != l3) { \
446 resample->h_resample (resample, l2, width); \
447 resample->h_resample (resample, l3, width); \
448 } \
449 } \
450 if (l0 != l1 && l2 != l3) { \
451 for (i = 0; i < width; i++) { \
452 tr0 = PR0(i), tr1 = PR2(i); \
453 tb0 = PB0(i), tb1 = PB2(i); \
454 \
455 PR0(i) = FILT_7_1 (tr0, tr1); \
456 PB0(i) = FILT_7_1 (tb0, tb1); \
457 PR1(i) = FILT_5_3 (tr0, tr1); \
458 PB1(i) = FILT_5_3 (tb0, tb1); \
459 PR2(i) = FILT_3_5 (tr0, tr1); \
460 PB2(i) = FILT_3_5 (tb0, tb1); \
461 PR3(i) = FILT_1_7 (tr0, tr1); \
462 PB3(i) = FILT_1_7 (tb0, tb1); \
463 } \
464 } \
465 }
466 /* 4x vertical upsampling interlaced without cositing
467 *
468 */
469 #define MAKE_UPSAMPLE_VI4(name,type) \
470 static void \
471 video_chroma_up_vi4_##name (GstVideoChromaResample *resample, \
472 gpointer lines[], gint width) \
473 { \
474 /* FIXME */ \
475 if (resample->h_resample) { \
476 resample->h_resample (resample, lines[0], width); \
477 } \
478 }
479
480 /* 4x horizontal downsampling without cositing
481 *
482 * +------ (a + 3*b + 3*c + d + 4) >> 3
483 * |
484 * v
485 * ---O-------O---
486 * x x x x x x x x
487 * a b c d e f g h
488 */
489 #define MAKE_DOWNSAMPLE_H4(name,type) \
490 static void \
491 video_chroma_down_h4_##name (GstVideoChromaResample *resample, \
492 gpointer pixels, gint width) \
493 { \
494 type *p = pixels; \
495 gint i; \
496 \
497 for (i = 0; i < width - 4; i += 4) { \
498 type tr0 = PR(i), tr1 = PR(i+1), tr2 = PR(i+2), tr3 = PR(i+3); \
499 type tb0 = PB(i), tb1 = PB(i+1), tb2 = PB(i+2), tb3 = PB(i+3); \
500 \
501 PR(i) = FILT_1_3_3_1 (tr0, tr1, tr2, tr3); \
502 PB(i) = FILT_1_3_3_1 (tb0, tb1, tb2, tb3); \
503 } \
504 }
505
506 /* 4x vertical downsampling without cositing
507 *
508 * a x--x--x-
509 * b x--x--x-
510 * O O O <---- (a + 3*b + 3*c + d + 4) >> 4
511 * c x--x--x-
512 * d x--x--x-
513 * e x--x--x-
514 * f x--x--x-
515 * O O O
516 * g x--x--x-
517 * h x--x--x-
518 */
519 #define MAKE_DOWNSAMPLE_V4(name,type) \
520 static void \
521 video_chroma_down_v4_##name (GstVideoChromaResample *resample, \
522 gpointer lines[], gint width) \
523 { \
524 type *l0 = lines[0]; \
525 type *l1 = lines[1]; \
526 type *l2 = lines[2]; \
527 type *l3 = lines[3]; \
528 type *d = l0; \
529 \
530 video_orc_chroma_down_v4_##name(d, l0, l1, l2, l3, width); \
531 \
532 if (resample->h_resample) \
533 resample->h_resample (resample, l0, width); \
534 }
535 /* 4x vertical downsampling interlaced without cositing
536 *
537 */
538 #define MAKE_DOWNSAMPLE_VI4(name,type) \
539 static void \
540 video_chroma_down_vi4_##name (GstVideoChromaResample *resample, \
541 gpointer lines[], gint width) \
542 { \
543 /* FIXME */ \
544 if (resample->h_resample) { \
545 resample->h_resample (resample, lines[0], width); \
546 } \
547 }
548
549 MAKE_UPSAMPLE_H4 (u16, guint16);
550 MAKE_UPSAMPLE_H4 (u8, guint8);
551 MAKE_UPSAMPLE_V4 (u16, guint16);
552 MAKE_UPSAMPLE_V4 (u8, guint8);
553 MAKE_UPSAMPLE_VI4 (u16, guint16);
554 MAKE_UPSAMPLE_VI4 (u8, guint8);
555 MAKE_DOWNSAMPLE_H4 (u16, guint16);
556 MAKE_DOWNSAMPLE_H4 (u8, guint8);
557 MAKE_DOWNSAMPLE_V4 (u16, guint16);
558 MAKE_DOWNSAMPLE_V4 (u8, guint8);
559 MAKE_DOWNSAMPLE_VI4 (u16, guint16);
560 MAKE_DOWNSAMPLE_VI4 (u8, guint8);
561
562 /* 2x horizontal upsampling with cositing
563 *
564 * a +------ (a + b + 1) >> 1
565 * | |
566 * v v
567 * O-O-O-O
568 * x x
569 * a b
570 */
571 #define MAKE_UPSAMPLE_H2_CS_ORC(name,type) \
572 static void \
573 video_chroma_up_h2_cs_##name (GstVideoChromaResample *resample, \
574 gpointer pixels, gint width) \
575 { \
576 type *p = pixels; \
577 /* ORC version is slower */ \
578 video_orc_chroma_up_h2_cs_##name (p, p, p, width-1); \
579 }
580
581 #define MAKE_UPSAMPLE_H2_CS(name,type) \
582 static void \
583 video_chroma_up_h2_cs_##name (GstVideoChromaResample *resample, \
584 gpointer pixels, gint width) \
585 { \
586 type *p = pixels; \
587 gint i; \
588 \
589 for (i = 1; i < width - 1; i += 2) { \
590 PR(i) = FILT_1_1 (PR(i-1), PR(i+1)); \
591 PB(i) = FILT_1_1 (PB(i-1), PB(i+1)); \
592 } \
593 }
594 /* 2x vertical upsampling with cositing
595 *
596 * a x O--O--O- <---- a
597 * O--O--O- <---- (a + b + 1) >> 1
598 * b x O--O--O-
599 * O--O--O-
600 */
601 #define MAKE_UPSAMPLE_V2_CS(name,type) \
602 static void \
603 video_chroma_up_v2_cs_##name (GstVideoChromaResample *resample, \
604 gpointer lines[], gint width) \
605 { \
606 /* FIXME */ \
607 if (resample->h_resample) { \
608 resample->h_resample (resample, lines[0], width); \
609 } \
610 }
611 /* 2x vertical upsampling interlaced with cositing
612 *
613 */
614 #define MAKE_UPSAMPLE_VI2_CS(name,type) \
615 static void \
616 video_chroma_up_vi2_cs_##name (GstVideoChromaResample *resample, \
617 gpointer lines[], gint width) \
618 { \
619 /* FIXME */ \
620 if (resample->h_resample) { \
621 resample->h_resample (resample, lines[0], width); \
622 } \
623 }
624
625 /* 2x horizontal downsampling with cositing
626 *
627 * a
628 * | +------ (b + 2*c + d + 2) >> 2
629 * v v
630 * O---O---O---
631 * x x x x x x
632 * a b c d e f
633 */
634 #define MAKE_DOWNSAMPLE_H2_CS(name,type) \
635 static void \
636 video_chroma_down_h2_cs_##name (GstVideoChromaResample *resample, \
637 gpointer pixels, gint width) \
638 { \
639 type *p = pixels; \
640 gint i; \
641 \
642 if (width < 2) \
643 return; \
644 \
645 PR(0) = FILT_3_1 (PR(0), PR(1)); \
646 PB(0) = FILT_3_1 (PB(0), PB(1)); \
647 \
648 for (i = 2; i < width - 2; i += 2) { \
649 PR(i) = FILT_1_2_1 (PR(i-1), PR(i), PR(i+1)); \
650 PB(i) = FILT_1_2_1 (PB(i-1), PB(i), PB(i+1)); \
651 } \
652 if (i < width) { \
653 PR(i) = FILT_1_3 (PR(i-1), PR(i)); \
654 PB(i) = FILT_1_3 (PB(i-1), PB(i)); \
655 } \
656 }
657 /* 2x vertical downsampling with cositing
658 *
659 * a x O--O--O- <---- a
660 * b x --------
661 * c x O--O--O- <---- (b + 2*c + d + 2) >> 2
662 * d x --------
663 * e x O--O--O-
664 * f x --------
665 */
666 #define MAKE_DOWNSAMPLE_V2_CS(name,type) \
667 static void \
668 video_chroma_down_v2_cs_##name (GstVideoChromaResample *resample, \
669 gpointer lines[], gint width) \
670 { \
671 /* FIXME */ \
672 if (resample->h_resample) { \
673 resample->h_resample (resample, lines[0], width); \
674 } \
675 }
676 /* 2x vertical downsampling interlaced with cositing
677 *
678 */
679 #define MAKE_DOWNSAMPLE_VI2_CS(name,type) \
680 static void \
681 video_chroma_down_vi2_cs_##name (GstVideoChromaResample *resample, \
682 gpointer lines[], gint width) \
683 { \
684 /* FIXME */ \
685 if (resample->h_resample) { \
686 resample->h_resample (resample, lines[0], width); \
687 } \
688 }
689
690 MAKE_UPSAMPLE_H2_CS (u16, guint16);
691 MAKE_UPSAMPLE_H2_CS (u8, guint8);
692 MAKE_UPSAMPLE_V2_CS (u16, guint16);
693 MAKE_UPSAMPLE_V2_CS (u8, guint8);
694 MAKE_UPSAMPLE_VI2_CS (u16, guint16);
695 MAKE_UPSAMPLE_VI2_CS (u8, guint8);
696 MAKE_DOWNSAMPLE_H2_CS (u16, guint16);
697 MAKE_DOWNSAMPLE_H2_CS (u8, guint8);
698 MAKE_DOWNSAMPLE_V2_CS (u16, guint16);
699 MAKE_DOWNSAMPLE_V2_CS (u8, guint8);
700 MAKE_DOWNSAMPLE_VI2_CS (u16, guint16);
701 MAKE_DOWNSAMPLE_VI2_CS (u8, guint8);
702
703 /* 4x horizontal upsampling with cositing
704 *
705 * +---------- (3*a + b + 2) >> 2
706 * a | +-------- ( a + b + 1) >> 1
707 * | | | +------ ( a + 3*b + 2) >> 2
708 * v v v v
709 * O-O-O-O-O-O-O-O
710 * x x
711 * a b
712 */
713 #define MAKE_UPSAMPLE_H4_CS(name,type) \
714 static void \
715 video_chroma_up_h4_cs_##name (GstVideoChromaResample *resample, \
716 gpointer pixels, gint width) \
717 { \
718 type *p = pixels; \
719 gint i; \
720 \
721 for (i = 0; i < width - 4; i += 4) { \
722 type tr0 = PR(i), tr1 = PR(i+4); \
723 type tb0 = PB(i), tb1 = PB(i+4); \
724 \
725 PR(i+1) = FILT_3_1 (tr0, tr1); \
726 PB(i+1) = FILT_3_1 (tb0, tb1); \
727 PR(i+2) = FILT_1_1 (tr0, tr1); \
728 PB(i+2) = FILT_1_1 (tb0, tb1); \
729 PR(i+3) = FILT_1_3 (tr0, tr1); \
730 PB(i+3) = FILT_1_3 (tb0, tb1); \
731 } \
732 }
733 /* 4x vertical upsampling with cositing
734 *
735 * a x O--O--O- <---- a
736 * O--O--O- <---- (3*a + b + 2) >> 2
737 * O--O--O- <---- ( a + b + 1) >> 1
738 * O--O--O- <---- ( a + 3*b + 2) >> 2
739 * b x O--O--O-
740 * O--O--O-
741 */
742 #define MAKE_UPSAMPLE_V4_CS(name,type) \
743 static void \
744 video_chroma_up_v4_cs_##name (GstVideoChromaResample *resample, \
745 gpointer lines[], gint width) \
746 { \
747 /* FIXME */ \
748 if (resample->h_resample) { \
749 resample->h_resample (resample, lines[0], width); \
750 } \
751 }
752 /* 4x vertical upsampling interlaced with cositing
753 *
754 */
755 #define MAKE_UPSAMPLE_VI4_CS(name,type) \
756 static void \
757 video_chroma_up_vi4_cs_##name (GstVideoChromaResample *resample, \
758 gpointer lines[], gint width) \
759 { \
760 /* FIXME */ \
761 if (resample->h_resample) { \
762 resample->h_resample (resample, lines[0], width); \
763 } \
764 }
765 /* 4x horizontal downsampling with cositing
766 *
767 * a
768 * | +------ (b + 2*c + 3*d + 4*e + 3*f + 2*g + h + 8) >> 16
769 * v v
770 * O-------O-------
771 * x x x x x x x x
772 * a b c d e f g h
773 */
774 #define MAKE_DOWNSAMPLE_H4_CS(name,type) \
775 static void \
776 video_chroma_down_h4_cs_##name (GstVideoChromaResample *resample, \
777 gpointer pixels, gint width) \
778 { \
779 type *p = pixels; \
780 gint i; \
781 \
782 if (width < 4) \
783 return; \
784 \
785 PR(0) = FILT_10_3_2_1 (PR(0), PR(1), PR(2), PR(3)); \
786 PB(0) = FILT_10_3_2_1 (PB(0), PB(1), PB(2), PB(3)); \
787 \
788 for (i = 4; i < width - 4; i += 4) { \
789 PR(i) = FILT_1_2_3_4_3_2_1 (PR(i-3), PR(i-2), PR(i-1), PR(i), PR(i+1), PR(i+2), PR(i+3)); \
790 PB(i) = FILT_1_2_3_4_3_2_1 (PB(i-3), PB(i-2), PB(i-1), PB(i), PB(i+1), PB(i+2), PB(i+3)); \
791 } \
792 if (i < width) { \
793 PR(i) = FILT_1_2_3_10 (PR(i-3), PR(i-2), PR(i-1), PR(i)); \
794 PB(i) = FILT_1_2_3_10 (PB(i-3), PB(i-2), PB(i-1), PB(i)); \
795 } \
796 }
797 /* 4x vertical downsampling with cositing
798 *
799 * a x O--O--O- <---- a
800 * b x --------
801 * c x --------
802 * d x --------
803 * e x O--O--O- <---- (b + 2*c + 3*d + 4*e + 3*f + 2*g + h + 8) >> 16
804 * f x --------
805 * g x --------
806 * h x --------
807 * i x O--O--O-
808 * j x --------
809 */
810 #define MAKE_DOWNSAMPLE_V4_CS(name,type) \
811 static void \
812 video_chroma_down_v4_cs_##name (GstVideoChromaResample *resample, \
813 gpointer lines[], gint width) \
814 { \
815 /* FIXME */ \
816 if (resample->h_resample) { \
817 resample->h_resample (resample, lines[0], width); \
818 } \
819 }
820 /* 4x vertical downsampling interlaced with cositing
821 *
822 */
823 #define MAKE_DOWNSAMPLE_VI4_CS(name,type) \
824 static void \
825 video_chroma_down_vi4_cs_##name (GstVideoChromaResample *resample, \
826 gpointer lines[], gint width) \
827 { \
828 /* FIXME */ \
829 if (resample->h_resample) { \
830 resample->h_resample (resample, lines[0], width); \
831 } \
832 }
833
834 MAKE_UPSAMPLE_H4_CS (u16, guint16);
835 MAKE_UPSAMPLE_H4_CS (u8, guint8);
836 MAKE_UPSAMPLE_V4_CS (u16, guint16);
837 MAKE_UPSAMPLE_V4_CS (u8, guint8);
838 MAKE_UPSAMPLE_VI4_CS (u16, guint16);
839 MAKE_UPSAMPLE_VI4_CS (u8, guint8);
840 MAKE_DOWNSAMPLE_H4_CS (u16, guint16);
841 MAKE_DOWNSAMPLE_H4_CS (u8, guint8);
842 MAKE_DOWNSAMPLE_V4_CS (u16, guint16);
843 MAKE_DOWNSAMPLE_V4_CS (u8, guint8);
844 MAKE_DOWNSAMPLE_VI4_CS (u16, guint16);
845 MAKE_DOWNSAMPLE_VI4_CS (u8, guint8);
846
847 typedef struct
848 {
849 void (*resample) (GstVideoChromaResample * resample, gpointer pixels,
850 gint width);
851 } HorizResampler;
852
853 static const HorizResampler h_resamplers[] = {
854 {NULL},
855 {video_chroma_up_h2_u8},
856 {video_chroma_down_h2_u8},
857 {video_chroma_up_h2_u16},
858 {video_chroma_down_h2_u16},
859 {video_chroma_up_h2_cs_u8},
860 {video_chroma_down_h2_cs_u8},
861 {video_chroma_up_h2_cs_u16},
862 {video_chroma_down_h2_cs_u16},
863 {video_chroma_up_h4_u8},
864 {video_chroma_down_h4_u8},
865 {video_chroma_up_h4_u16},
866 {video_chroma_down_h4_u16},
867 {video_chroma_up_h4_cs_u8},
868 {video_chroma_down_h4_cs_u8},
869 {video_chroma_up_h4_cs_u16},
870 {video_chroma_down_h4_cs_u16}
871 };
872
873 typedef struct
874 {
875 void (*resample) (GstVideoChromaResample * resample, gpointer lines[],
876 gint width);
877 guint n_lines;
878 gint offset;
879 } VertResampler;
880
881 static void
video_chroma_none(GstVideoChromaResample * resample,gpointer lines[],gint width)882 video_chroma_none (GstVideoChromaResample * resample,
883 gpointer lines[], gint width)
884 {
885 if (resample->h_resample)
886 resample->h_resample (resample, lines[0], width);
887 }
888
889 static const VertResampler v_resamplers[] = {
890 {video_chroma_none, 1, 0},
891 {video_chroma_up_v2_u8, 2, -1},
892 {video_chroma_down_v2_u8, 2, 0},
893 /* 16 bits */
894 {video_chroma_up_v2_u16, 2, -1},
895 {video_chroma_down_v2_u16, 2, 0},
896 /* cosited */
897 {video_chroma_up_v2_cs_u8, 1, 0}, /* IMPLEMENT ME */
898 {video_chroma_down_v2_cs_u8, 1, 0}, /* IMPLEMENT ME */
899 {video_chroma_up_v2_cs_u16, 1, 0}, /* IMPLEMENT ME */
900 {video_chroma_down_v2_cs_u16, 1, 0}, /* IMPLEMENT ME */
901 /* 4x */
902 {video_chroma_up_v4_u8, 4, -2},
903 {video_chroma_down_v4_u8, 4, 0},
904 {video_chroma_up_v4_u16, 4, -2},
905 {video_chroma_down_v4_u16, 4, 0},
906 {video_chroma_up_v4_cs_u8, 1, 0}, /* IMPLEMENT ME */
907 {video_chroma_down_v4_cs_u8, 1, 0}, /* IMPLEMENT ME */
908 {video_chroma_up_v4_cs_u16, 1, 0}, /* IMPLEMENT ME */
909 {video_chroma_down_v4_cs_u16, 1, 0}, /* IMPLEMENT ME */
910 /* interlaced */
911 {video_chroma_up_vi2_u8, 4, -2},
912 {video_chroma_down_vi2_u8, 1, 0}, /* IMPLEMENT ME */
913 {video_chroma_up_vi2_u16, 4, -2},
914 {video_chroma_down_vi2_u16, 1, 0}, /* IMPLEMENT ME */
915 {video_chroma_up_vi2_cs_u8, 1, 0}, /* IMPLEMENT ME */
916 {video_chroma_down_vi2_cs_u8, 1, 0}, /* IMPLEMENT ME */
917 {video_chroma_up_vi2_cs_u16, 1, 0}, /* IMPLEMENT ME */
918 {video_chroma_down_vi2_cs_u16, 1, 0}, /* IMPLEMENT ME */
919 {video_chroma_up_vi4_u8, 1, 0}, /* IMPLEMENT ME */
920 {video_chroma_down_vi4_u8, 1, 0}, /* IMPLEMENT ME */
921 {video_chroma_up_vi4_u16, 1, 0}, /* IMPLEMENT ME */
922 {video_chroma_down_vi4_u16, 1, 0}, /* IMPLEMENT ME */
923 {video_chroma_up_vi4_cs_u8, 1, 0}, /* IMPLEMENT ME */
924 {video_chroma_down_vi4_cs_u8, 1, 0}, /* IMPLEMENT ME */
925 {video_chroma_up_vi4_cs_u16, 1, 0}, /* IMPLEMENT ME */
926 {video_chroma_down_vi4_cs_u16, 1, 0}, /* IMPLEMENT ME */
927 };
928
929 /**
930 * gst_video_chroma_resample_new: (skip)
931 * @method: a #GstVideoChromaMethod
932 * @site: a #GstVideoChromaSite
933 * @flags: #GstVideoChromaFlags
934 * @format: the #GstVideoFormat
935 * @h_factor: horizontal resampling factor
936 * @v_factor: vertical resampling factor
937 *
938 * Create a new resampler object for the given parameters. When @h_factor or
939 * @v_factor is > 0, upsampling will be used, otherwise subsampling is
940 * performed.
941 *
942 * Returns: a new #GstVideoChromaResample that should be freed with
943 * gst_video_chroma_resample_free() after usage.
944 */
945 GstVideoChromaResample *
gst_video_chroma_resample_new(GstVideoChromaMethod method,GstVideoChromaSite site,GstVideoChromaFlags flags,GstVideoFormat format,gint h_factor,gint v_factor)946 gst_video_chroma_resample_new (GstVideoChromaMethod method,
947 GstVideoChromaSite site, GstVideoChromaFlags flags,
948 GstVideoFormat format, gint h_factor, gint v_factor)
949 {
950 GstVideoChromaResample *result;
951 guint cosite, h_index, v_index, bits;
952
953 /* no resampling */
954 if (h_factor == 0 && v_factor == 0)
955 return NULL;
956
957 if (format == GST_VIDEO_FORMAT_AYUV)
958 bits = 8;
959 else if (format == GST_VIDEO_FORMAT_AYUV64)
960 bits = 16;
961 else
962 return NULL;
963
964 cosite = (site & GST_VIDEO_CHROMA_SITE_H_COSITED ? 1 : 0);
965 if (h_factor == 0)
966 h_index = 0;
967 else
968 h_index =
969 ((ABS (h_factor) - 1) * 8) + (cosite ? 4 : 0) + (bits ==
970 16 ? 2 : 0) + (h_factor < 0 ? 1 : 0) + 1;
971
972 GST_DEBUG ("h_resample %d, factor %d, cosite %d", h_index, h_factor, cosite);
973
974 cosite = (site & GST_VIDEO_CHROMA_SITE_V_COSITED ? 1 : 0);
975 if (v_factor == 0)
976 v_index = 0;
977 else
978 v_index =
979 ((ABS (v_factor) - 1) * 8) + (cosite ? 4 : 0) + (bits ==
980 16 ? 2 : 0) + (v_factor < 0 ? 1 : 0) + 1;
981
982 if (flags & GST_VIDEO_CHROMA_FLAG_INTERLACED)
983 v_index += 16;
984
985 GST_DEBUG ("v_resample %d, factor %d, cosite %d", v_index, v_factor, cosite);
986
987 result = g_slice_new (GstVideoChromaResample);
988 result->method = method;
989 result->site = site;
990 result->flags = flags;
991 result->format = format;
992 result->h_factor = h_factor;
993 result->v_factor = v_factor;
994 result->h_resample = h_resamplers[h_index].resample;
995 result->v_resample = v_resamplers[v_index].resample;
996 result->n_lines = v_resamplers[v_index].n_lines;
997 result->offset = v_resamplers[v_index].offset;
998
999 GST_DEBUG ("resample %p, bits %d, n_lines %u, offset %d", result, bits,
1000 result->n_lines, result->offset);
1001
1002 return result;
1003 }
1004
1005 /**
1006 * gst_video_chroma_resample_get_info:
1007 * @resample: a #GstVideoChromaResample
1008 * @n_lines: the number of input lines
1009 * @offset: the first line
1010 *
1011 * The resampler must be fed @n_lines at a time. The first line should be
1012 * at @offset.
1013 */
1014 void
gst_video_chroma_resample_get_info(GstVideoChromaResample * resample,guint * n_lines,gint * offset)1015 gst_video_chroma_resample_get_info (GstVideoChromaResample * resample,
1016 guint * n_lines, gint * offset)
1017 {
1018 g_return_if_fail (resample != NULL);
1019
1020 if (n_lines)
1021 *n_lines = resample->n_lines;
1022 if (offset)
1023 *offset = resample->offset;
1024 }
1025
1026 /**
1027 * gst_video_chroma_resample_free:
1028 * @resample: a #GstVideoChromaResample
1029 *
1030 * Free @resample
1031 */
1032 void
gst_video_chroma_resample_free(GstVideoChromaResample * resample)1033 gst_video_chroma_resample_free (GstVideoChromaResample * resample)
1034 {
1035 g_return_if_fail (resample != NULL);
1036
1037 g_slice_free (GstVideoChromaResample, resample);
1038 }
1039
1040 /**
1041 * gst_video_chroma_resample:
1042 * @resample: a #GstVideoChromaResample
1043 * @lines: pixel lines
1044 * @width: the number of pixels on one line
1045 *
1046 * Perform resampling of @width chroma pixels in @lines.
1047 */
1048 void
gst_video_chroma_resample(GstVideoChromaResample * resample,gpointer lines[],gint width)1049 gst_video_chroma_resample (GstVideoChromaResample * resample,
1050 gpointer lines[], gint width)
1051 {
1052 g_return_if_fail (resample != NULL);
1053
1054 resample->v_resample (resample, lines, width);
1055 }
1056