video-info: Add unit test for overflow checks
[platform/upstream/gstreamer.git] / tests / check / libs / video.c
1 /* GStreamer unit test for video
2  *
3  * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4  * Copyright (C) <2006> Jan Schmidt <thaytan@mad.scientist.com>
5  * Copyright (C) <2008,2011> Tim-Philipp Müller <tim centricular net>
6  * Copyright (C) <2012> Collabora Ltd. <tim.muller@collabora.co.uk>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #ifdef HAVE_VALGRIND
29 # include <valgrind/valgrind.h>
30 #endif
31
32 #include <unistd.h>
33
34 #include <gst/check/gstcheck.h>
35
36 #include <gst/video/video.h>
37 #include <gst/video/gstvideometa.h>
38 #include <gst/video/video-overlay-composition.h>
39 #include <string.h>
40
41 /* These are from the current/old videotestsrc; we check our new public API
42  * in libgstvideo against the old one to make sure the sizes and offsets
43  * end up the same */
44
45 typedef struct paintinfo_struct paintinfo;
46 struct paintinfo_struct
47 {
48   unsigned char *dest;          /* pointer to first byte of video data */
49   unsigned char *yp, *up, *vp;  /* pointers to first byte of each component
50                                  * for both packed/planar YUV and RGB */
51   unsigned char *ap;            /* pointer to first byte of alpha component */
52   unsigned char *endptr;        /* pointer to byte beyond last video data */
53   int ystride;
54   int ustride;
55   int vstride;
56   int width;
57   int height;
58 };
59
60 struct fourcc_list_struct
61 {
62   const char *fourcc;
63   const char *name;
64   int bitspp;
65   void (*paint_setup) (paintinfo * p, unsigned char *dest);
66 };
67
68 static void paint_setup_I420 (paintinfo * p, unsigned char *dest);
69 static void paint_setup_YV12 (paintinfo * p, unsigned char *dest);
70 static void paint_setup_YUY2 (paintinfo * p, unsigned char *dest);
71 static void paint_setup_UYVY (paintinfo * p, unsigned char *dest);
72 static void paint_setup_YVYU (paintinfo * p, unsigned char *dest);
73 static void paint_setup_IYU2 (paintinfo * p, unsigned char *dest);
74 static void paint_setup_Y41B (paintinfo * p, unsigned char *dest);
75 static void paint_setup_Y42B (paintinfo * p, unsigned char *dest);
76 static void paint_setup_GRAY8 (paintinfo * p, unsigned char *dest);
77 static void paint_setup_AYUV (paintinfo * p, unsigned char *dest);
78
79 #if 0
80 static void paint_setup_IMC1 (paintinfo * p, unsigned char *dest);
81 static void paint_setup_IMC2 (paintinfo * p, unsigned char *dest);
82 static void paint_setup_IMC3 (paintinfo * p, unsigned char *dest);
83 static void paint_setup_IMC4 (paintinfo * p, unsigned char *dest);
84 #endif
85 static void paint_setup_YUV9 (paintinfo * p, unsigned char *dest);
86 static void paint_setup_YVU9 (paintinfo * p, unsigned char *dest);
87
88 int fourcc_get_size (struct fourcc_list_struct *fourcc, int w, int h);
89
90 struct fourcc_list_struct fourcc_list[] = {
91 /* packed */
92   {"YUY2", "YUY2", 16, paint_setup_YUY2},
93   {"UYVY", "UYVY", 16, paint_setup_UYVY},
94   {"Y422", "Y422", 16, paint_setup_UYVY},
95   {"UYNV", "UYNV", 16, paint_setup_UYVY},       /* FIXME: UYNV? */
96   {"YVYU", "YVYU", 16, paint_setup_YVYU},
97   {"AYUV", "AYUV", 32, paint_setup_AYUV},
98
99   /* interlaced */
100   /*{   "IUYV", "IUY2", 16, paint_setup_YVYU }, */
101
102   /* inverted */
103   /*{   "cyuv", "cyuv", 16, paint_setup_YVYU }, */
104
105   /*{   "Y41P", "Y41P", 12, paint_setup_YVYU }, */
106
107   /* interlaced */
108   /*{   "IY41", "IY41", 12, paint_setup_YVYU }, */
109
110   /*{   "Y211", "Y211", 8, paint_setup_YVYU }, */
111
112   /*{   "Y41T", "Y41T", 12, paint_setup_YVYU }, */
113   /*{   "Y42P", "Y42P", 16, paint_setup_YVYU }, */
114   /*{   "CLJR", "CLJR", 8, paint_setup_YVYU }, */
115   /*{   "IYU1", "IYU1", 12, paint_setup_YVYU }, */
116   {"IYU2", "IYU2", 24, paint_setup_IYU2},
117
118 /* planar */
119   /* YVU9 */
120   {"YVU9", "YVU9", 9, paint_setup_YVU9},
121   /* YUV9 */
122   {"YUV9", "YUV9", 9, paint_setup_YUV9},
123   /* IF09 */
124   /* YV12 */
125   {"YV12", "YV12", 12, paint_setup_YV12},
126   /* I420 */
127   {"I420", "I420", 12, paint_setup_I420},
128   /* NV12 */
129   /* NV21 */
130 #if 0
131   /* IMC1 */
132   {"IMC1", "IMC1", 16, paint_setup_IMC1},
133   /* IMC2 */
134   {"IMC2", "IMC2", 12, paint_setup_IMC2},
135   /* IMC3 */
136   {"IMC3", "IMC3", 16, paint_setup_IMC3},
137   /* IMC4 */
138   {"IMC4", "IMC4", 12, paint_setup_IMC4},
139 #endif
140   /* CLPL */
141   /* Y41B */
142   {"Y41B", "Y41B", 12, paint_setup_Y41B},
143   /* Y42B */
144   {"Y42B", "Y42B", 16, paint_setup_Y42B},
145   /* GRAY8 grayscale */
146   {"GRAY8", "GRAY8", 8, paint_setup_GRAY8}
147 };
148
149 /* returns the size in bytes for one video frame of the given dimensions
150  * given the fourcc */
151 int
152 fourcc_get_size (struct fourcc_list_struct *fourcc, int w, int h)
153 {
154   paintinfo pi = { NULL, };
155   paintinfo *p = &pi;
156
157   p->width = w;
158   p->height = h;
159
160   fourcc->paint_setup (p, NULL);
161
162   return (unsigned long) p->endptr;
163 }
164
165 static void
166 paint_setup_I420 (paintinfo * p, unsigned char *dest)
167 {
168   p->yp = dest;
169   p->ystride = GST_ROUND_UP_4 (p->width);
170   p->up = p->yp + p->ystride * GST_ROUND_UP_2 (p->height);
171   p->ustride = GST_ROUND_UP_8 (p->width) / 2;
172   p->vp = p->up + p->ustride * GST_ROUND_UP_2 (p->height) / 2;
173   p->vstride = GST_ROUND_UP_8 (p->ystride) / 2;
174   p->endptr = p->vp + p->vstride * GST_ROUND_UP_2 (p->height) / 2;
175 }
176
177 static void
178 paint_setup_YV12 (paintinfo * p, unsigned char *dest)
179 {
180   p->yp = dest;
181   p->ystride = GST_ROUND_UP_4 (p->width);
182   p->vp = p->yp + p->ystride * GST_ROUND_UP_2 (p->height);
183   p->vstride = GST_ROUND_UP_8 (p->ystride) / 2;
184   p->up = p->vp + p->vstride * GST_ROUND_UP_2 (p->height) / 2;
185   p->ustride = GST_ROUND_UP_8 (p->ystride) / 2;
186   p->endptr = p->up + p->ustride * GST_ROUND_UP_2 (p->height) / 2;
187 }
188
189 static void
190 paint_setup_AYUV (paintinfo * p, unsigned char *dest)
191 {
192   p->ap = dest;
193   p->yp = dest + 1;
194   p->up = dest + 2;
195   p->vp = dest + 3;
196   p->ystride = p->width * 4;
197   p->endptr = dest + p->ystride * p->height;
198 }
199
200 static void
201 paint_setup_YUY2 (paintinfo * p, unsigned char *dest)
202 {
203   p->yp = dest;
204   p->up = dest + 1;
205   p->vp = dest + 3;
206   p->ystride = GST_ROUND_UP_2 (p->width) * 2;
207   p->endptr = dest + p->ystride * p->height;
208 }
209
210 static void
211 paint_setup_UYVY (paintinfo * p, unsigned char *dest)
212 {
213   p->yp = dest + 1;
214   p->up = dest;
215   p->vp = dest + 2;
216   p->ystride = GST_ROUND_UP_2 (p->width) * 2;
217   p->endptr = dest + p->ystride * p->height;
218 }
219
220 static void
221 paint_setup_YVYU (paintinfo * p, unsigned char *dest)
222 {
223   p->yp = dest;
224   p->up = dest + 3;
225   p->vp = dest + 1;
226   p->ystride = GST_ROUND_UP_2 (p->width) * 2;
227   p->endptr = dest + p->ystride * p->height;
228 }
229
230 static void
231 paint_setup_IYU2 (paintinfo * p, unsigned char *dest)
232 {
233   /* untested */
234   p->yp = dest + 1;
235   p->up = dest + 0;
236   p->vp = dest + 2;
237   p->ystride = GST_ROUND_UP_4 (p->width * 3);
238   p->endptr = dest + p->ystride * p->height;
239 }
240
241 static void
242 paint_setup_Y41B (paintinfo * p, unsigned char *dest)
243 {
244   p->yp = dest;
245   p->ystride = GST_ROUND_UP_4 (p->width);
246   p->up = p->yp + p->ystride * p->height;
247   p->ustride = GST_ROUND_UP_16 (p->width) / 4;
248   p->vp = p->up + p->ustride * p->height;
249   p->vstride = GST_ROUND_UP_16 (p->width) / 4;
250   p->endptr = p->vp + p->vstride * p->height;
251 }
252
253 static void
254 paint_setup_Y42B (paintinfo * p, unsigned char *dest)
255 {
256   p->yp = dest;
257   p->ystride = GST_ROUND_UP_4 (p->width);
258   p->up = p->yp + p->ystride * p->height;
259   p->ustride = GST_ROUND_UP_8 (p->width) / 2;
260   p->vp = p->up + p->ustride * p->height;
261   p->vstride = GST_ROUND_UP_8 (p->width) / 2;
262   p->endptr = p->vp + p->vstride * p->height;
263 }
264
265 static void
266 paint_setup_GRAY8 (paintinfo * p, unsigned char *dest)
267 {
268   /* untested */
269   p->yp = dest;
270   p->ystride = GST_ROUND_UP_4 (p->width);
271   p->endptr = dest + p->ystride * p->height;
272 }
273
274 #if 0
275 static void
276 paint_setup_IMC1 (paintinfo * p, unsigned char *dest)
277 {
278   p->yp = dest;
279   p->up = dest + p->width * p->height;
280   p->vp = dest + p->width * p->height + p->width * p->height / 2;
281 }
282
283 static void
284 paint_setup_IMC2 (paintinfo * p, unsigned char *dest)
285 {
286   p->yp = dest;
287   p->vp = dest + p->width * p->height;
288   p->up = dest + p->width * p->height + p->width / 2;
289 }
290
291 static void
292 paint_setup_IMC3 (paintinfo * p, unsigned char *dest)
293 {
294   p->yp = dest;
295   p->up = dest + p->width * p->height + p->width * p->height / 2;
296   p->vp = dest + p->width * p->height;
297 }
298
299 static void
300 paint_setup_IMC4 (paintinfo * p, unsigned char *dest)
301 {
302   p->yp = dest;
303   p->vp = dest + p->width * p->height + p->width / 2;
304   p->up = dest + p->width * p->height;
305 }
306 #endif
307
308 static void
309 paint_setup_YVU9 (paintinfo * p, unsigned char *dest)
310 {
311   p->yp = dest;
312   p->ystride = GST_ROUND_UP_4 (p->width);
313   p->vp = p->yp + p->ystride * p->height;
314   p->vstride = GST_ROUND_UP_4 (p->ystride / 4);
315   p->up = p->vp + p->vstride * (GST_ROUND_UP_4 (p->height) / 4);
316   p->ustride = GST_ROUND_UP_4 (p->ystride / 4);
317   p->endptr = p->up + p->ustride * (GST_ROUND_UP_4 (p->height) / 4);
318 }
319
320 static void
321 paint_setup_YUV9 (paintinfo * p, unsigned char *dest)
322 {
323   p->yp = dest;
324   p->ystride = GST_ROUND_UP_4 (p->width);
325   p->up = p->yp + p->ystride * p->height;
326   p->ustride = GST_ROUND_UP_4 (p->ystride / 4);
327   p->vp = p->up + p->ustride * (GST_ROUND_UP_4 (p->height) / 4);
328   p->vstride = GST_ROUND_UP_4 (p->ystride / 4);
329   p->endptr = p->vp + p->vstride * (GST_ROUND_UP_4 (p->height) / 4);
330 }
331
332 #define gst_video_format_is_packed video_format_is_packed
333 static gboolean
334 video_format_is_packed (GstVideoFormat fmt)
335 {
336   switch (fmt) {
337     case GST_VIDEO_FORMAT_I420:
338     case GST_VIDEO_FORMAT_YV12:
339     case GST_VIDEO_FORMAT_Y41B:
340     case GST_VIDEO_FORMAT_Y42B:
341     case GST_VIDEO_FORMAT_GRAY8:
342     case GST_VIDEO_FORMAT_YUV9:
343     case GST_VIDEO_FORMAT_YVU9:
344       return FALSE;
345     case GST_VIDEO_FORMAT_IYU1:
346     case GST_VIDEO_FORMAT_IYU2:
347     case GST_VIDEO_FORMAT_YUY2:
348     case GST_VIDEO_FORMAT_YVYU:
349     case GST_VIDEO_FORMAT_UYVY:
350     case GST_VIDEO_FORMAT_VYUY:
351     case GST_VIDEO_FORMAT_AYUV:
352     case GST_VIDEO_FORMAT_RGBx:
353     case GST_VIDEO_FORMAT_BGRx:
354     case GST_VIDEO_FORMAT_xRGB:
355     case GST_VIDEO_FORMAT_xBGR:
356     case GST_VIDEO_FORMAT_RGBA:
357     case GST_VIDEO_FORMAT_BGRA:
358     case GST_VIDEO_FORMAT_ARGB:
359     case GST_VIDEO_FORMAT_ABGR:
360     case GST_VIDEO_FORMAT_RGB:
361     case GST_VIDEO_FORMAT_BGR:
362     case GST_VIDEO_FORMAT_RGB8P:
363       return TRUE;
364     default:
365       g_return_val_if_reached (FALSE);
366   }
367   return FALSE;
368 }
369
370 static gint
371 get_num_formats (void)
372 {
373   gint num_formats = 100;
374   fail_unless (gst_video_format_to_string (num_formats) == NULL);
375   while (gst_video_format_to_string (num_formats) == NULL)
376     --num_formats;
377   GST_INFO ("number of known video formats: %d", num_formats);
378   return num_formats + 1;
379 }
380
381 GST_START_TEST (test_video_formats_all)
382 {
383   GstStructure *s;
384   const GValue *val, *list_val;
385   GstCaps *caps;
386   guint num, n, num_formats;
387
388   num_formats = get_num_formats ();
389
390   caps = gst_caps_from_string ("video/x-raw, format=" GST_VIDEO_FORMATS_ALL);
391   s = gst_caps_get_structure (caps, 0);
392   val = gst_structure_get_value (s, "format");
393   fail_unless (val != NULL);
394   fail_unless (GST_VALUE_HOLDS_LIST (val));
395   num = gst_value_list_get_size (val);
396   fail_unless (num > 0);
397   for (n = 0; n < num; ++n) {
398     const gchar *fmt_str;
399
400     list_val = gst_value_list_get_value (val, n);
401     fail_unless (G_VALUE_HOLDS_STRING (list_val));
402     fmt_str = g_value_get_string (list_val);
403     GST_INFO ("format: %s", fmt_str);
404     fail_if (gst_video_format_from_string (fmt_str) ==
405         GST_VIDEO_FORMAT_UNKNOWN);
406   }
407   /* Take into account GST_VIDEO_FORMAT_ENCODED and UNKNOWN */
408   fail_unless_equals_int (num, num_formats - 2);
409
410   gst_caps_unref (caps);
411 }
412
413 GST_END_TEST;
414
415 #define WIDTH 77
416 #define HEIGHT 20
417 GST_START_TEST (test_video_formats_pack_unpack)
418 {
419   guint n, num_formats;
420
421   num_formats = get_num_formats ();
422
423   for (n = GST_VIDEO_FORMAT_ENCODED + 1; n < num_formats; ++n) {
424     const GstVideoFormatInfo *vfinfo, *unpackinfo;
425     GstVideoFormat fmt = n;
426     GstVideoInfo vinfo;
427     gpointer data[GST_VIDEO_MAX_PLANES];
428     gint stride[GST_VIDEO_MAX_PLANES];
429     guint8 *vdata, *unpack_data;
430     gsize vsize, unpack_size;
431     guint p;
432
433     GST_INFO ("testing %s", gst_video_format_to_string (fmt));
434
435     vfinfo = gst_video_format_get_info (fmt);
436     fail_unless (vfinfo != NULL);
437
438     unpackinfo = gst_video_format_get_info (vfinfo->unpack_format);
439     fail_unless (unpackinfo != NULL);
440
441     gst_video_info_init (&vinfo);
442     gst_video_info_set_format (&vinfo, fmt, WIDTH, HEIGHT);
443     vsize = GST_VIDEO_INFO_SIZE (&vinfo);
444     vdata = g_malloc (vsize);
445     memset (vdata, 0x99, vsize);
446
447     g_assert (vfinfo->pack_lines == 1);
448
449     unpack_size =
450         GST_VIDEO_FORMAT_INFO_BITS (unpackinfo) *
451         GST_VIDEO_FORMAT_INFO_N_COMPONENTS (unpackinfo) *
452         GST_ROUND_UP_16 (WIDTH);
453     unpack_data = g_malloc (unpack_size);
454
455     for (p = 0; p < GST_VIDEO_INFO_N_PLANES (&vinfo); ++p) {
456       data[p] = vdata + GST_VIDEO_INFO_PLANE_OFFSET (&vinfo, p);
457       stride[p] = GST_VIDEO_INFO_PLANE_STRIDE (&vinfo, p);
458     }
459
460     /* now unpack */
461     vfinfo->unpack_func (vfinfo, GST_VIDEO_PACK_FLAG_NONE, unpack_data, data,
462         stride, 0, 0, WIDTH);
463
464     /* and pack */
465     vfinfo->pack_func (vfinfo, GST_VIDEO_PACK_FLAG_NONE, unpack_data,
466         unpack_size, data, stride, GST_VIDEO_CHROMA_SITE_UNKNOWN, 0, WIDTH);
467
468     /* now unpack */
469     vfinfo->unpack_func (vfinfo, GST_VIDEO_PACK_FLAG_NONE, unpack_data, data,
470         stride, 0, HEIGHT - 1, WIDTH);
471
472     /* and pack */
473     vfinfo->pack_func (vfinfo, GST_VIDEO_PACK_FLAG_NONE, unpack_data,
474         unpack_size, data, stride, GST_VIDEO_CHROMA_SITE_UNKNOWN, HEIGHT - 1,
475         WIDTH);
476
477     g_free (unpack_data);
478     g_free (vdata);
479   }
480 }
481
482 GST_END_TEST;
483 #undef WIDTH
484 #undef HEIGHT
485
486 GST_START_TEST (test_video_formats)
487 {
488   guint i;
489
490   for (i = 0; i < G_N_ELEMENTS (fourcc_list); ++i) {
491     const GstVideoFormatInfo *vf_info;
492     GstVideoFormat fmt;
493     const gchar *s;
494     guint32 fourcc;
495     guint w, h;
496
497     s = fourcc_list[i].fourcc;
498     fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
499     fmt = gst_video_format_from_fourcc (fourcc);
500
501     if (fmt == GST_VIDEO_FORMAT_UNKNOWN) {
502       GST_DEBUG ("Unknown format %s, skipping tests", fourcc_list[i].fourcc);
503       continue;
504     }
505
506     vf_info = gst_video_format_get_info (fmt);
507     fail_unless (vf_info != NULL);
508
509     fail_unless_equals_int (GST_VIDEO_FORMAT_INFO_FORMAT (vf_info), fmt);
510
511     GST_INFO ("Fourcc %s, packed=%d", fourcc_list[i].fourcc,
512         gst_video_format_is_packed (fmt));
513
514     fail_unless (GST_VIDEO_FORMAT_INFO_IS_YUV (vf_info));
515
516     /* use any non-NULL pointer so we can compare against NULL */
517     {
518       paintinfo paintinfo = { 0, };
519       fourcc_list[i].paint_setup (&paintinfo, (unsigned char *) s);
520       if (paintinfo.ap != NULL) {
521         fail_unless (GST_VIDEO_FORMAT_INFO_HAS_ALPHA (vf_info));
522       } else {
523         fail_if (GST_VIDEO_FORMAT_INFO_HAS_ALPHA (vf_info));
524       }
525     }
526
527     for (w = 1; w <= 65; ++w) {
528       for (h = 1; h <= 65; ++h) {
529         GstVideoInfo vinfo;
530         paintinfo paintinfo = { 0, };
531         guint off0, off1, off2, off3;
532         guint cs0, cs1, cs2, cs3;
533         guint size;
534
535         GST_LOG ("%s, %dx%d", fourcc_list[i].fourcc, w, h);
536
537         gst_video_info_init (&vinfo);
538         gst_video_info_set_format (&vinfo, fmt, w, h);
539
540         paintinfo.width = w;
541         paintinfo.height = h;
542         fourcc_list[i].paint_setup (&paintinfo, NULL);
543         fail_unless_equals_int (GST_VIDEO_INFO_COMP_STRIDE (&vinfo, 0),
544             paintinfo.ystride);
545         if (!gst_video_format_is_packed (fmt)
546             && GST_VIDEO_INFO_N_PLANES (&vinfo) <= 2) {
547           /* planar */
548           fail_unless_equals_int (GST_VIDEO_INFO_COMP_STRIDE (&vinfo, 1),
549               paintinfo.ustride);
550           fail_unless_equals_int (GST_VIDEO_INFO_COMP_STRIDE (&vinfo, 2),
551               paintinfo.vstride);
552           /* check component_width * height against offsets/size somehow? */
553         }
554
555         size = GST_VIDEO_INFO_SIZE (&vinfo);
556         off0 = GST_VIDEO_INFO_COMP_OFFSET (&vinfo, 0);
557         off1 = GST_VIDEO_INFO_COMP_OFFSET (&vinfo, 1);
558         off2 = GST_VIDEO_INFO_COMP_OFFSET (&vinfo, 2);
559
560         GST_INFO ("size %d <> %d", size, (int) ((guintptr) paintinfo.endptr));
561         GST_INFO ("off0 %d <> %d", off0, (int) ((guintptr) paintinfo.yp));
562         GST_INFO ("off1 %d <> %d", off1, (int) ((guintptr) paintinfo.up));
563         GST_INFO ("off2 %d <> %d", off2, (int) ((guintptr) paintinfo.vp));
564
565         fail_unless_equals_int (size, (unsigned long) paintinfo.endptr);
566         fail_unless_equals_int (off0, (unsigned long) paintinfo.yp);
567         fail_unless_equals_int (off1, (unsigned long) paintinfo.up);
568         fail_unless_equals_int (off2, (unsigned long) paintinfo.vp);
569
570         /* should be 0 if there's no alpha component */
571         off3 = GST_VIDEO_INFO_COMP_OFFSET (&vinfo, 3);
572         fail_unless_equals_int (off3, (unsigned long) paintinfo.ap);
573
574         cs0 = GST_VIDEO_INFO_COMP_WIDTH (&vinfo, 0) *
575             GST_VIDEO_INFO_COMP_HEIGHT (&vinfo, 0);
576         cs1 = GST_VIDEO_INFO_COMP_WIDTH (&vinfo, 1) *
577             GST_VIDEO_INFO_COMP_HEIGHT (&vinfo, 1);
578         cs2 = GST_VIDEO_INFO_COMP_WIDTH (&vinfo, 2) *
579             GST_VIDEO_INFO_COMP_HEIGHT (&vinfo, 2);
580
581         /* GST_LOG ("cs0=%d,cs1=%d,cs2=%d,off0=%d,off1=%d,off2=%d,size=%d",
582            cs0, cs1, cs2, off0, off1, off2, size); */
583
584         if (!gst_video_format_is_packed (fmt))
585           fail_unless (cs0 <= off1);
586
587         if (GST_VIDEO_FORMAT_INFO_HAS_ALPHA (vinfo.finfo)) {
588           cs3 = GST_VIDEO_INFO_COMP_WIDTH (&vinfo, 3) *
589               GST_VIDEO_INFO_COMP_HEIGHT (&vinfo, 2);
590           fail_unless (cs3 < size);
591           /* U/V/alpha shouldn't take up more space than the Y component */
592           fail_if (cs1 > cs0, "cs1 (%d) should be <= cs0 (%d)", cs1, cs0);
593           fail_if (cs2 > cs0, "cs2 (%d) should be <= cs0 (%d)", cs2, cs0);
594           fail_if (cs3 > cs0, "cs3 (%d) should be <= cs0 (%d)", cs3, cs0);
595
596           /* all components together shouldn't take up more space than size */
597           fail_unless (cs0 + cs1 + cs2 + cs3 <= size);
598         } else {
599           /* U/V shouldn't take up more space than the Y component */
600           fail_if (cs1 > cs0, "cs1 (%d) should be <= cs0 (%d)", cs1, cs0);
601           fail_if (cs2 > cs0, "cs2 (%d) should be <= cs0 (%d)", cs2, cs0);
602
603           /* all components together shouldn't take up more space than size */
604           fail_unless (cs0 + cs1 + cs2 <= size,
605               "cs0 (%d) + cs1 (%d) + cs2 (%d) should be <= size (%d)",
606               cs0, cs1, cs2, size);
607         }
608       }
609     }
610   }
611 }
612
613 GST_END_TEST;
614
615 GST_START_TEST (test_video_formats_overflow)
616 {
617   GstVideoInfo vinfo;
618
619   gst_video_info_init (&vinfo);
620
621   fail_unless (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB, 32768,
622           32767));
623   /* fails due to simplification: we forbid some things that would in theory be fine.
624    * We assume a 128 byte alignment for the width currently
625    * fail_unless (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB, 32767, 32768));
626    */
627   fail_if (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB, 32768,
628           32768));
629
630   fail_if (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB,
631           G_MAXINT / 2, G_MAXINT));
632   fail_if (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB, G_MAXINT,
633           G_MAXINT / 2));
634   fail_if (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB,
635           G_MAXINT / 2, G_MAXINT / 2));
636   fail_if (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB, G_MAXINT,
637           G_MAXINT));
638   fail_if (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB,
639           G_MAXUINT / 2, G_MAXUINT));
640   fail_if (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB, G_MAXUINT,
641           G_MAXUINT / 2));
642   fail_if (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB,
643           G_MAXUINT / 2, G_MAXUINT / 2));
644   fail_if (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB, G_MAXUINT,
645           G_MAXUINT));
646
647   fail_unless (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB,
648           1073741824 - 128, 1));
649   fail_if (gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_ARGB, 1073741824,
650           1));
651
652 }
653
654 GST_END_TEST;
655
656 GST_START_TEST (test_video_formats_rgb)
657 {
658   GstVideoInfo vinfo;
659   gint width, height, framerate_n, framerate_d, par_n, par_d;
660   GstCaps *caps;
661   GstStructure *structure;
662
663   gst_video_info_init (&vinfo);
664   gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_RGB, 800, 600);
665   vinfo.par_n = 1;
666   vinfo.par_d = 1;
667   vinfo.fps_n = 0;
668   vinfo.fps_d = 1;
669   caps = gst_video_info_to_caps (&vinfo);
670   structure = gst_caps_get_structure (caps, 0);
671
672   fail_unless (gst_structure_get_int (structure, "width", &width));
673   fail_unless (gst_structure_get_int (structure, "height", &height));
674   fail_unless (gst_structure_get_fraction (structure, "framerate", &framerate_n,
675           &framerate_d));
676   fail_unless (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
677           &par_n, &par_d));
678
679   fail_unless (width == 800);
680   fail_unless (height == 600);
681   fail_unless (framerate_n == 0);
682   fail_unless (framerate_d == 1);
683   fail_unless (par_n == 1);
684   fail_unless (par_d == 1);
685
686   gst_caps_unref (caps);
687 }
688
689 GST_END_TEST;
690
691
692 GST_START_TEST (test_video_formats_rgba_large_dimension)
693 {
694   GstVideoInfo vinfo;
695   gint width, height, framerate_n, framerate_d, par_n, par_d;
696   GstCaps *caps;
697   GstStructure *structure;
698
699   gst_video_info_init (&vinfo);
700   gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_RGBA, 29700, 21000);
701   vinfo.par_n = 1;
702   vinfo.par_d = 1;
703   vinfo.fps_n = 0;
704   vinfo.fps_d = 1;
705   caps = gst_video_info_to_caps (&vinfo);
706   structure = gst_caps_get_structure (caps, 0);
707
708   fail_unless (gst_structure_get_int (structure, "width", &width));
709   fail_unless (gst_structure_get_int (structure, "height", &height));
710   fail_unless (gst_structure_get_fraction (structure, "framerate", &framerate_n,
711           &framerate_d));
712   fail_unless (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
713           &par_n, &par_d));
714
715   fail_unless (width == 29700);
716   fail_unless (height == 21000);
717   fail_unless (framerate_n == 0);
718   fail_unless (framerate_d == 1);
719   fail_unless (par_n == 1);
720   fail_unless (par_d == 1);
721   fail_unless (vinfo.size == (gsize) 29700 * 21000 * 4);
722
723   gst_caps_unref (caps);
724 }
725
726 GST_END_TEST;
727
728 GST_START_TEST (test_dar_calc)
729 {
730   guint display_ratio_n, display_ratio_d;
731
732   /* Ensure that various Display Ratio calculations are correctly done */
733   /* video 768x576, par 16/15, display par 16/15 = 4/3 */
734   fail_unless (gst_video_calculate_display_ratio (&display_ratio_n,
735           &display_ratio_d, 768, 576, 16, 15, 16, 15));
736   fail_unless (display_ratio_n == 4 && display_ratio_d == 3);
737
738   /* video 720x480, par 32/27, display par 1/1 = 16/9 */
739   fail_unless (gst_video_calculate_display_ratio (&display_ratio_n,
740           &display_ratio_d, 720, 480, 32, 27, 1, 1));
741   fail_unless (display_ratio_n == 16 && display_ratio_d == 9);
742
743   /* video 360x288, par 533333/500000, display par 16/15 = 
744    * dar 1599999/1600000 */
745   fail_unless (gst_video_calculate_display_ratio (&display_ratio_n,
746           &display_ratio_d, 360, 288, 533333, 500000, 16, 15));
747   fail_unless (display_ratio_n == 1599999 && display_ratio_d == 1280000);
748 }
749
750 GST_END_TEST;
751
752 GST_START_TEST (test_parse_caps_rgb)
753 {
754   struct
755   {
756     const gchar *tmpl_caps_string;
757     GstVideoFormat fmt;
758   } formats[] = {
759     /* 24 bit */
760     {
761     GST_VIDEO_CAPS_MAKE ("RGB"), GST_VIDEO_FORMAT_RGB}, {
762     GST_VIDEO_CAPS_MAKE ("BGR"), GST_VIDEO_FORMAT_BGR},
763         /* 32 bit (no alpha) */
764     {
765     GST_VIDEO_CAPS_MAKE ("RGBx"), GST_VIDEO_FORMAT_RGBx}, {
766     GST_VIDEO_CAPS_MAKE ("xRGB"), GST_VIDEO_FORMAT_xRGB}, {
767     GST_VIDEO_CAPS_MAKE ("BGRx"), GST_VIDEO_FORMAT_BGRx}, {
768     GST_VIDEO_CAPS_MAKE ("xBGR"), GST_VIDEO_FORMAT_xBGR},
769         /* 32 bit (with alpha) */
770     {
771     GST_VIDEO_CAPS_MAKE ("RGBA"), GST_VIDEO_FORMAT_RGBA}, {
772     GST_VIDEO_CAPS_MAKE ("ARGB"), GST_VIDEO_FORMAT_ARGB}, {
773     GST_VIDEO_CAPS_MAKE ("BGRA"), GST_VIDEO_FORMAT_BGRA}, {
774     GST_VIDEO_CAPS_MAKE ("ABGR"), GST_VIDEO_FORMAT_ABGR},
775         /* 16 bit */
776     {
777     GST_VIDEO_CAPS_MAKE ("RGB16"), GST_VIDEO_FORMAT_RGB16}, {
778     GST_VIDEO_CAPS_MAKE ("BGR16"), GST_VIDEO_FORMAT_BGR16}, {
779     GST_VIDEO_CAPS_MAKE ("RGB15"), GST_VIDEO_FORMAT_RGB15}, {
780     GST_VIDEO_CAPS_MAKE ("BGR15"), GST_VIDEO_FORMAT_BGR15}
781   };
782   gint i;
783
784   for (i = 0; i < G_N_ELEMENTS (formats); ++i) {
785     GstVideoInfo vinfo;
786     GstCaps *caps, *caps2;
787
788     caps = gst_caps_from_string (formats[i].tmpl_caps_string);
789     fail_unless (caps != NULL);
790     gst_caps_set_simple (caps, "width", G_TYPE_INT, 2 * (i + 1), "height",
791         G_TYPE_INT, i + 1, "framerate", GST_TYPE_FRACTION, 15, 1,
792         "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
793         "interlace-mode", G_TYPE_STRING, "progressive",
794         "colorimetry", G_TYPE_STRING, "1:1:0:0",
795         "multiview-mode", G_TYPE_STRING, "mono",
796         "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, 0,
797         GST_FLAG_SET_MASK_EXACT, NULL);
798     g_assert (gst_caps_is_fixed (caps));
799
800     GST_DEBUG ("testing caps: %" GST_PTR_FORMAT, caps);
801
802     gst_video_info_init (&vinfo);
803     fail_unless (gst_video_info_from_caps (&vinfo, caps));
804     fail_unless_equals_int (GST_VIDEO_INFO_FORMAT (&vinfo), formats[i].fmt);
805     fail_unless_equals_int (GST_VIDEO_INFO_WIDTH (&vinfo), 2 * (i + 1));
806     fail_unless_equals_int (GST_VIDEO_INFO_HEIGHT (&vinfo), i + 1);
807
808     /* make sure they're serialised back correctly */
809     caps2 = gst_video_info_to_caps (&vinfo);
810     fail_unless (caps2 != NULL);
811     if (!gst_caps_is_equal (caps, caps2)) {
812       gchar *caps1s = gst_caps_to_string (caps);
813       gchar *caps2s = gst_caps_to_string (caps2);
814       fail ("caps [%s] not equal to caps2 [%s]", caps1s, caps2s);
815       g_free (caps1s);
816       g_free (caps2s);
817     }
818
819     gst_caps_unref (caps);
820     gst_caps_unref (caps2);
821   }
822 }
823
824 GST_END_TEST;
825
826 GST_START_TEST (test_parse_caps_multiview)
827 {
828   gint i, j;
829   GstVideoMultiviewMode modes[] = {
830     GST_VIDEO_MULTIVIEW_MODE_MONO,
831     GST_VIDEO_MULTIVIEW_MODE_LEFT,
832     GST_VIDEO_MULTIVIEW_MODE_RIGHT,
833     GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE,
834     GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX,
835     GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED,
836     GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED,
837     GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM,
838     GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD,
839     GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME,
840     GST_VIDEO_MULTIVIEW_MODE_MULTIVIEW_FRAME_BY_FRAME,
841     GST_VIDEO_MULTIVIEW_MODE_SEPARATED,
842   };
843   GstVideoMultiviewFlags flags[] = {
844     GST_VIDEO_MULTIVIEW_FLAGS_NONE,
845     GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST,
846     GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLIPPED,
847     GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLOPPED,
848     GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLIPPED,
849     GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLOPPED,
850     GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO,
851     GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO |
852         GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST,
853     GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO |
854         GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLIPPED
855   };
856
857   for (i = 0; i < G_N_ELEMENTS (modes); i++) {
858     for (j = 0; j < G_N_ELEMENTS (flags); j++) {
859       GstVideoInfo vinfo;
860       GstCaps *caps;
861
862       gst_video_info_init (&vinfo);
863       gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_I420, 320, 240);
864
865       GST_VIDEO_INFO_MULTIVIEW_MODE (&vinfo) = modes[i];
866       GST_VIDEO_INFO_MULTIVIEW_FLAGS (&vinfo) = flags[j];
867
868       caps = gst_video_info_to_caps (&vinfo);
869       fail_if (caps == NULL);
870       GST_LOG ("mview mode %d flags %x -> caps %" GST_PTR_FORMAT,
871           modes[i], flags[j], caps);
872
873       fail_unless (gst_video_info_from_caps (&vinfo, caps));
874
875       GST_LOG ("mview mode %d flags %x -> info mode %d flags %x",
876           modes[i], flags[j], GST_VIDEO_INFO_MULTIVIEW_MODE (&vinfo),
877           GST_VIDEO_INFO_MULTIVIEW_FLAGS (&vinfo));
878
879       fail_unless (GST_VIDEO_INFO_MULTIVIEW_MODE (&vinfo) == modes[i],
880           "Expected multiview mode %d got mode %d", modes[i],
881           GST_VIDEO_INFO_MULTIVIEW_MODE (&vinfo));
882       fail_unless (GST_VIDEO_INFO_MULTIVIEW_FLAGS (&vinfo) == flags[j],
883           "Expected multiview flags 0x%x got 0x%x", flags[j],
884           GST_VIDEO_INFO_MULTIVIEW_FLAGS (&vinfo));
885
886       gst_caps_unref (caps);
887     }
888   }
889 }
890
891 GST_END_TEST;
892
893 typedef struct
894 {
895   const gchar *string_from;
896   const gchar *string_to;
897   const gchar *name;
898   GstVideoColorimetry color;
899 } ColorimetryTest;
900
901 #define MAKE_COLORIMETRY_TEST(s1,s2,n,r,m,t,p) { s1, s2, n,         \
902     { GST_VIDEO_COLOR_RANGE ##r, GST_VIDEO_COLOR_MATRIX_ ##m,       \
903     GST_VIDEO_TRANSFER_ ##t, GST_VIDEO_COLOR_PRIMARIES_ ##p } }
904
905 GST_START_TEST (test_parse_colorimetry)
906 {
907   ColorimetryTest tests[] = {
908     MAKE_COLORIMETRY_TEST ("bt601", "bt601", "bt601",
909         _16_235, BT601, BT709, SMPTE170M),
910     MAKE_COLORIMETRY_TEST ("2:4:5:4", "bt601", "bt601",
911         _16_235, BT601, BT709, SMPTE170M),
912     MAKE_COLORIMETRY_TEST ("bt709", "bt709", "bt709",
913         _16_235, BT709, BT709, BT709),
914     MAKE_COLORIMETRY_TEST ("smpte240m", "smpte240m", "smpte240m",
915         _16_235, SMPTE240M, SMPTE240M, SMPTE240M),
916     MAKE_COLORIMETRY_TEST ("sRGB", "sRGB", "sRGB",
917         _0_255, RGB, SRGB, BT709),
918     MAKE_COLORIMETRY_TEST ("bt2020", "bt2020", "bt2020",
919         _16_235, BT2020, BT2020_12, BT2020),
920     MAKE_COLORIMETRY_TEST ("1:4:0:0", "1:4:0:0", NULL,
921         _0_255, BT601, UNKNOWN, UNKNOWN),
922   };
923   gint i;
924
925   for (i = 0; i < G_N_ELEMENTS (tests); i++) {
926     const ColorimetryTest *test = &tests[i];
927     GstVideoColorimetry color;
928     gchar *string;
929
930     fail_unless (gst_video_colorimetry_from_string (&color, test->string_from));
931     fail_unless_equals_int (color.range, test->color.range);
932     fail_unless_equals_int (color.matrix, test->color.matrix);
933     fail_unless_equals_int (color.transfer, test->color.transfer);
934     fail_unless_equals_int (color.primaries, test->color.primaries);
935
936     string = gst_video_colorimetry_to_string (&color);
937     fail_unless_equals_string (string, test->string_to);
938     g_free (string);
939
940     fail_unless (gst_video_colorimetry_is_equal (&color, &test->color));
941
942     if (test->name)
943       fail_unless (gst_video_colorimetry_matches (&color, test->name));
944   }
945 }
946
947 GST_END_TEST;
948
949 GST_START_TEST (test_events)
950 {
951   GstEvent *e;
952   gboolean in_still;
953
954   e = gst_video_event_new_still_frame (TRUE);
955   fail_if (e == NULL, "Failed to create still frame event");
956   fail_unless (gst_video_event_parse_still_frame (e, &in_still),
957       "Failed to parse still frame event");
958   fail_unless (gst_video_event_parse_still_frame (e, NULL),
959       "Failed to parse still frame event w/ in_still == NULL");
960   fail_unless (in_still == TRUE);
961   gst_event_unref (e);
962
963   e = gst_video_event_new_still_frame (FALSE);
964   fail_if (e == NULL, "Failed to create still frame event");
965   fail_unless (gst_video_event_parse_still_frame (e, &in_still),
966       "Failed to parse still frame event");
967   fail_unless (gst_video_event_parse_still_frame (e, NULL),
968       "Failed to parse still frame event w/ in_still == NULL");
969   fail_unless (in_still == FALSE);
970   gst_event_unref (e);
971 }
972
973 GST_END_TEST;
974
975 GST_START_TEST (test_convert_frame)
976 {
977   GstVideoInfo vinfo;
978   GstCaps *from_caps, *to_caps;
979   GstBuffer *from_buffer;
980   GstSample *from_sample, *to_sample;
981   GError *error = NULL;
982   gint i;
983   GstMapInfo map;
984
985   gst_debug_set_threshold_for_name ("default", GST_LEVEL_NONE);
986
987   from_buffer = gst_buffer_new_and_alloc (640 * 480 * 4);
988
989   gst_buffer_map (from_buffer, &map, GST_MAP_WRITE);
990   for (i = 0; i < 640 * 480; i++) {
991     map.data[4 * i + 0] = 0;    /* x */
992     map.data[4 * i + 1] = 255;  /* R */
993     map.data[4 * i + 2] = 0;    /* G */
994     map.data[4 * i + 3] = 0;    /* B */
995   }
996   gst_buffer_unmap (from_buffer, &map);
997
998   gst_video_info_init (&vinfo);
999   gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_xRGB, 640, 480);
1000   vinfo.fps_n = 25;
1001   vinfo.fps_d = 1;
1002   vinfo.par_n = 1;
1003   vinfo.par_d = 1;
1004   from_caps = gst_video_info_to_caps (&vinfo);
1005
1006   from_sample = gst_sample_new (from_buffer, from_caps, NULL, NULL);
1007
1008   to_caps =
1009       gst_caps_from_string
1010       ("something/that, does=(string)not, exist=(boolean)FALSE");
1011
1012   to_sample =
1013       gst_video_convert_sample (from_sample, to_caps,
1014       GST_CLOCK_TIME_NONE, &error);
1015   fail_if (to_sample != NULL);
1016   fail_unless (error != NULL);
1017   g_error_free (error);
1018   error = NULL;
1019
1020   gst_caps_unref (to_caps);
1021   gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_I420, 240, 320);
1022   vinfo.fps_n = 25;
1023   vinfo.fps_d = 1;
1024   vinfo.par_n = 1;
1025   vinfo.par_d = 2;
1026   to_caps = gst_video_info_to_caps (&vinfo);
1027
1028   to_sample =
1029       gst_video_convert_sample (from_sample, to_caps,
1030       GST_CLOCK_TIME_NONE, &error);
1031   fail_unless (to_sample != NULL);
1032   fail_unless (error == NULL);
1033
1034   gst_buffer_unref (from_buffer);
1035   gst_caps_unref (from_caps);
1036   gst_sample_unref (from_sample);
1037   gst_sample_unref (to_sample);
1038   gst_caps_unref (to_caps);
1039 }
1040
1041 GST_END_TEST;
1042
1043 typedef struct
1044 {
1045   GMainLoop *loop;
1046   GstSample *sample;
1047   GError *error;
1048 } ConvertFrameContext;
1049
1050 static void
1051 convert_sample_async_callback (GstSample * sample, GError * err,
1052     ConvertFrameContext * cf_data)
1053 {
1054   cf_data->sample = sample;
1055   cf_data->error = err;
1056
1057   g_main_loop_quit (cf_data->loop);
1058 }
1059
1060 GST_START_TEST (test_convert_frame_async)
1061 {
1062   GstVideoInfo vinfo;
1063   GstCaps *from_caps, *to_caps;
1064   GstBuffer *from_buffer;
1065   GstSample *from_sample;
1066   gint i;
1067   GstMapInfo map;
1068   GMainLoop *loop;
1069   ConvertFrameContext cf_data = { NULL, NULL, NULL };
1070
1071   gst_debug_set_threshold_for_name ("default", GST_LEVEL_NONE);
1072
1073   from_buffer = gst_buffer_new_and_alloc (640 * 480 * 4);
1074
1075   gst_buffer_map (from_buffer, &map, GST_MAP_WRITE);
1076   for (i = 0; i < 640 * 480; i++) {
1077     map.data[4 * i + 0] = 0;    /* x */
1078     map.data[4 * i + 1] = 255;  /* R */
1079     map.data[4 * i + 2] = 0;    /* G */
1080     map.data[4 * i + 3] = 0;    /* B */
1081   }
1082   gst_buffer_unmap (from_buffer, &map);
1083
1084   gst_video_info_init (&vinfo);
1085   gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_xRGB, 640, 470);
1086   vinfo.par_n = 1;
1087   vinfo.par_d = 1;
1088   vinfo.fps_n = 25;
1089   vinfo.fps_d = 1;
1090   from_caps = gst_video_info_to_caps (&vinfo);
1091
1092   to_caps =
1093       gst_caps_from_string
1094       ("something/that, does=(string)not, exist=(boolean)FALSE");
1095
1096   loop = cf_data.loop = g_main_loop_new (NULL, FALSE);
1097
1098   from_sample = gst_sample_new (from_buffer, from_caps, NULL, NULL);
1099   gst_buffer_unref (from_buffer);
1100   gst_caps_unref (from_caps);
1101
1102   gst_video_convert_sample_async (from_sample, to_caps,
1103       GST_CLOCK_TIME_NONE,
1104       (GstVideoConvertSampleCallback) convert_sample_async_callback, &cf_data,
1105       NULL);
1106
1107   g_main_loop_run (loop);
1108
1109   fail_if (cf_data.sample != NULL);
1110   fail_unless (cf_data.error != NULL);
1111   g_error_free (cf_data.error);
1112   cf_data.error = NULL;
1113
1114   gst_caps_unref (to_caps);
1115   gst_video_info_init (&vinfo);
1116   gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_I420, 240, 320);
1117   vinfo.par_n = 1;
1118   vinfo.par_d = 2;
1119   vinfo.fps_n = 25;
1120   vinfo.fps_d = 1;
1121   to_caps = gst_video_info_to_caps (&vinfo);
1122   gst_video_convert_sample_async (from_sample, to_caps,
1123       GST_CLOCK_TIME_NONE,
1124       (GstVideoConvertSampleCallback) convert_sample_async_callback, &cf_data,
1125       NULL);
1126   g_main_loop_run (loop);
1127   fail_unless (cf_data.sample != NULL);
1128   fail_unless (cf_data.error == NULL);
1129
1130   gst_sample_unref (cf_data.sample);
1131   gst_caps_unref (to_caps);
1132   gst_sample_unref (from_sample);
1133
1134   g_main_loop_unref (loop);
1135 }
1136
1137 GST_END_TEST;
1138
1139 GST_START_TEST (test_video_size_from_caps)
1140 {
1141   GstVideoInfo vinfo;
1142   GstCaps *caps;
1143
1144   caps = gst_caps_new_simple ("video/x-raw",
1145       "format", G_TYPE_STRING, "YV12",
1146       "width", G_TYPE_INT, 640,
1147       "height", G_TYPE_INT, 480, "framerate", GST_TYPE_FRACTION, 25, 1, NULL);
1148
1149   gst_video_info_init (&vinfo);
1150   fail_unless (gst_video_info_from_caps (&vinfo, caps));
1151   fail_unless (GST_VIDEO_INFO_SIZE (&vinfo) == (640 * 480 * 12 / 8));
1152
1153   gst_caps_unref (caps);
1154 }
1155
1156 GST_END_TEST;
1157
1158 GST_START_TEST (test_overlay_composition)
1159 {
1160   GstVideoOverlayComposition *comp1, *comp2;
1161   GstVideoOverlayRectangle *rect1, *rect2;
1162   GstVideoOverlayCompositionMeta *ometa;
1163   GstBuffer *pix1, *pix2, *buf;
1164   GstVideoMeta *vmeta;
1165   guint seq1, seq2;
1166   guint w, h, stride;
1167   gint x, y;
1168   guint8 val;
1169
1170   pix1 = gst_buffer_new_and_alloc (200 * sizeof (guint32) * 50);
1171   gst_buffer_memset (pix1, 0, 0, gst_buffer_get_size (pix1));
1172
1173   gst_buffer_add_video_meta (pix1, GST_VIDEO_FRAME_FLAG_NONE,
1174       GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB, 200, 50);
1175   rect1 = gst_video_overlay_rectangle_new_raw (pix1,
1176       600, 50, 300, 50, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1177
1178   gst_buffer_unref (pix1);
1179   pix1 = NULL;
1180
1181   comp1 = gst_video_overlay_composition_new (rect1);
1182   fail_unless (gst_video_overlay_composition_n_rectangles (comp1) == 1);
1183   fail_unless (gst_video_overlay_composition_get_rectangle (comp1, 0) == rect1);
1184   fail_unless (gst_video_overlay_composition_get_rectangle (comp1, 1) == NULL);
1185
1186   /* rectangle was created first, sequence number should be smaller */
1187   seq1 = gst_video_overlay_rectangle_get_seqnum (rect1);
1188   seq2 = gst_video_overlay_composition_get_seqnum (comp1);
1189   fail_unless (seq1 < seq2);
1190
1191   /* composition took own ref, so refcount is 2 now, so this should fail */
1192   ASSERT_CRITICAL (gst_video_overlay_rectangle_set_render_rectangle (rect1, 50,
1193           600, 300, 50));
1194
1195   /* drop our ref, so refcount is 1 (we know it will continue to be valid) */
1196   gst_video_overlay_rectangle_unref (rect1);
1197   gst_video_overlay_rectangle_set_render_rectangle (rect1, 50, 600, 300, 50);
1198
1199   comp2 = gst_video_overlay_composition_new (rect1);
1200   fail_unless (gst_video_overlay_composition_n_rectangles (comp2) == 1);
1201   fail_unless (gst_video_overlay_composition_get_rectangle (comp2, 0) == rect1);
1202   fail_unless (gst_video_overlay_composition_get_rectangle (comp2, 1) == NULL);
1203
1204   fail_unless (seq1 < gst_video_overlay_composition_get_seqnum (comp2));
1205   fail_unless (seq2 < gst_video_overlay_composition_get_seqnum (comp2));
1206
1207   /* now refcount is 2 again because comp2 has also taken a ref, so must fail */
1208   ASSERT_CRITICAL (gst_video_overlay_rectangle_set_render_rectangle (rect1, 0,
1209           0, 1, 1));
1210
1211   /* this should make a copy of the rectangles so drop the original
1212    * second ref on rect1 */
1213   comp2 = gst_video_overlay_composition_make_writable (comp2);
1214   gst_video_overlay_rectangle_set_render_rectangle (rect1, 51, 601, 301, 51);
1215
1216   rect2 = gst_video_overlay_composition_get_rectangle (comp2, 0);
1217   fail_unless (gst_video_overlay_composition_n_rectangles (comp2) == 1);
1218   fail_unless (gst_video_overlay_composition_get_rectangle (comp2, 0) == rect2);
1219   fail_unless (gst_video_overlay_composition_get_rectangle (comp2, 1) == NULL);
1220   fail_unless (rect1 != rect2);
1221
1222   gst_video_overlay_composition_add_rectangle (comp1, rect2);
1223   gst_video_overlay_composition_ref (comp1);
1224   ASSERT_CRITICAL (gst_video_overlay_composition_add_rectangle (comp1, rect2));
1225   gst_video_overlay_composition_unref (comp1);
1226
1227   /* make sure the copy really worked */
1228   gst_video_overlay_rectangle_get_render_rectangle (rect1, &x, &y, &w, &h);
1229   fail_unless_equals_int (x, 51);
1230   fail_unless_equals_int (y, 601);
1231   fail_unless_equals_int (w, 301);
1232   fail_unless_equals_int (h, 51);
1233
1234   /* get scaled pixbuf and touch last byte */
1235   pix1 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1236       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1237   stride = 4 * w;
1238   fail_unless (gst_buffer_get_size (pix1) > ((h - 1) * stride + (w * 4) - 1),
1239       "size %u vs. last pixel offset %u", gst_buffer_get_size (pix1),
1240       ((h - 1) * stride + (w * 4) - 1));
1241   gst_buffer_extract (pix1, ((h - 1) * stride + (w * 4) - 1), &val, 1);
1242   fail_unless_equals_int (val, 0);
1243
1244   gst_video_overlay_rectangle_get_render_rectangle (rect2, &x, &y, &w, &h);
1245   fail_unless_equals_int (x, 50);
1246   fail_unless_equals_int (y, 600);
1247   fail_unless_equals_int (w, 300);
1248   fail_unless_equals_int (h, 50);
1249
1250   /* get scaled pixbuf and touch last byte */
1251   pix2 = gst_video_overlay_rectangle_get_pixels_raw (rect2,
1252       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1253   stride = 4 * w;
1254   fail_unless (gst_buffer_get_size (pix2) > ((h - 1) * stride + (w * 4) - 1),
1255       "size %u vs. last pixel offset %u", gst_buffer_get_size (pix1),
1256       ((h - 1) * stride + (w * 4) - 1));
1257   gst_buffer_extract (pix2, ((h - 1) * stride + (w * 4) - 1), &val, 1);
1258   fail_unless_equals_int (val, 0);
1259
1260   /* get scaled pixbuf again, should be the same buffer as before (caching) */
1261   pix1 = gst_video_overlay_rectangle_get_pixels_raw (rect2,
1262       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1263   fail_unless (pix1 == pix2);
1264
1265   /* get in different format */
1266   pix1 = gst_video_overlay_rectangle_get_pixels_ayuv (rect2,
1267       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1268   fail_unless (pix1 != pix2);
1269   /* get it again, should be same (caching) */
1270   pix2 = gst_video_overlay_rectangle_get_pixels_ayuv (rect2,
1271       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1272   fail_unless (pix1 == pix2);
1273   /* get unscaled, should be different */
1274   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_ayuv (rect2,
1275       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1276   fail_unless (pix1 != pix2);
1277   /* but should be cached */
1278   pix1 = gst_video_overlay_rectangle_get_pixels_unscaled_ayuv (rect2,
1279       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1280   fail_unless (pix1 == pix2);
1281
1282   vmeta = gst_buffer_get_video_meta (pix1);
1283   fail_unless (vmeta != NULL);
1284   w = vmeta->width;
1285   h = vmeta->height;
1286   fail_unless_equals_int (w, 200);
1287   fail_unless_equals_int (h, 50);
1288   fail_unless_equals_int (vmeta->format,
1289       GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_YUV);
1290   fail_unless (gst_buffer_get_size (pix1) == w * h * 4);
1291   gst_buffer_extract (pix1, 0, &seq1, 4);
1292   fail_unless (seq1 != 0);
1293
1294   /* now compare the original unscaled ones */
1295   pix1 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1296       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1297   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect2,
1298       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1299
1300   vmeta = gst_buffer_get_video_meta (pix2);
1301   fail_unless (vmeta != NULL);
1302   w = vmeta->width;
1303   h = vmeta->height;
1304
1305   /* the original pixel buffers should be identical */
1306   fail_unless (pix1 == pix2);
1307   fail_unless_equals_int (w, 200);
1308   fail_unless_equals_int (h, 50);
1309   stride = 4 * w;
1310
1311   /* touch last byte */
1312   fail_unless (gst_buffer_get_size (pix1) > ((h - 1) * stride + (w * 4) - 1),
1313       "size %u vs. last pixel offset %u", gst_buffer_get_size (pix1),
1314       ((h - 1) * stride + (w * 4) - 1));
1315   gst_buffer_extract (pix1, ((h - 1) * stride + (w * 4) - 1), &val, 1);
1316   fail_unless_equals_int (val, 0);
1317
1318   /* test attaching and retrieving of compositions to/from buffers */
1319   buf = gst_buffer_new ();
1320   fail_unless (gst_buffer_get_video_overlay_composition_meta (buf) == NULL);
1321
1322   gst_buffer_ref (buf);
1323   /* buffer now has refcount of 2, so its metadata is not writable.
1324    * only check this if we are not running in valgrind, as it leaks */
1325 #ifdef HAVE_VALGRIND
1326   if (!RUNNING_ON_VALGRIND) {
1327     ASSERT_CRITICAL (gst_buffer_add_video_overlay_composition_meta (buf,
1328             comp1));
1329   }
1330 #endif
1331   gst_buffer_unref (buf);
1332   gst_buffer_add_video_overlay_composition_meta (buf, comp1);
1333   ometa = gst_buffer_get_video_overlay_composition_meta (buf);
1334   fail_unless (ometa != NULL);
1335   fail_unless (ometa->overlay == comp1);
1336   fail_unless (gst_buffer_remove_video_overlay_composition_meta (buf, ometa));
1337   gst_buffer_add_video_overlay_composition_meta (buf, comp2);
1338   ometa = gst_buffer_get_video_overlay_composition_meta (buf);
1339   fail_unless (ometa->overlay == comp2);
1340   fail_unless (gst_buffer_remove_video_overlay_composition_meta (buf, ometa));
1341   fail_unless (gst_buffer_get_video_overlay_composition_meta (buf) == NULL);
1342
1343   /* make sure the buffer cleans up its composition ref when unreffed */
1344   gst_buffer_add_video_overlay_composition_meta (buf, comp2);
1345   gst_buffer_unref (buf);
1346
1347   gst_video_overlay_composition_unref (comp2);
1348   gst_video_overlay_composition_unref (comp1);
1349 }
1350
1351 GST_END_TEST;
1352
1353 GST_START_TEST (test_overlay_composition_premultiplied_alpha)
1354 {
1355   GstVideoOverlayRectangle *rect1;
1356   GstVideoMeta *vmeta;
1357   GstBuffer *pix1, *pix2, *pix3, *pix4, *pix5;
1358   GstBuffer *pix6, *pix7, *pix8, *pix9, *pix10;
1359   guint8 *data5, *data7;
1360   guint w, h, w2, h2;
1361   GstMapInfo map;
1362
1363   pix1 = gst_buffer_new_and_alloc (200 * sizeof (guint32) * 50);
1364   gst_buffer_memset (pix1, 0, 0x80, gst_buffer_get_size (pix1));
1365
1366   gst_buffer_add_video_meta (pix1, GST_VIDEO_FRAME_FLAG_NONE,
1367       GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB, 200, 50);
1368   rect1 = gst_video_overlay_rectangle_new_raw (pix1,
1369       600, 50, 300, 50, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1370   gst_buffer_unref (pix1);
1371
1372   /* same flags, unscaled, should be the same buffer */
1373   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1374       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1375   fail_unless (pix1 == pix2);
1376
1377   /* same flags, but scaled */
1378   pix3 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1379       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1380   fail_if (pix3 == pix1 || pix3 == pix2);
1381
1382   /* same again, should hopefully get the same (cached) buffer as before */
1383   pix4 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1384       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1385   fail_unless (pix4 == pix3);
1386
1387   /* just to update the vars */
1388   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1389       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1390
1391   vmeta = gst_buffer_get_video_meta (pix2);
1392   fail_unless (vmeta != NULL);
1393   w = vmeta->width;
1394   h = vmeta->height;
1395
1396   /* now, let's try to get premultiplied alpha from the unpremultiplied input */
1397   pix5 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1398       GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
1399   fail_if (pix5 == pix1 || pix5 == pix2 || pix5 == pix3);
1400   vmeta = gst_buffer_get_video_meta (pix5);
1401   fail_unless (vmeta != NULL);
1402   w2 = vmeta->width;
1403   h2 = vmeta->height;
1404   fail_unless_equals_int (w, w2);
1405   fail_unless_equals_int (h, h2);
1406   fail_unless_equals_int (gst_buffer_get_size (pix2),
1407       gst_buffer_get_size (pix5));
1408   gst_buffer_map (pix5, &map, GST_MAP_READ);
1409   fail_if (gst_buffer_memcmp (pix2, 0, map.data, map.size) == 0);
1410   /* make sure it actually did what we expected it to do (input=0x80808080) */
1411   data5 = map.data;
1412 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1413   /* B - G - R - A */
1414   fail_unless_equals_int (data5[0], 0x40);
1415   fail_unless_equals_int (data5[1], 0x40);
1416   fail_unless_equals_int (data5[2], 0x40);
1417   fail_unless_equals_int (data5[3], 0x80);
1418 #else
1419   /* A - R - G - B */
1420   fail_unless_equals_int (data5[0], 0x80);
1421   fail_unless_equals_int (data5[1], 0x40);
1422   fail_unless_equals_int (data5[2], 0x40);
1423   fail_unless_equals_int (data5[3], 0x40);
1424 #endif
1425   gst_buffer_unmap (pix5, &map);
1426
1427   /* same again, now we should be getting back the same buffer as before,
1428    * as it should have been cached */
1429   pix6 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1430       GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
1431   fail_unless (pix6 == pix5);
1432
1433   /* just to update the stride var */
1434   pix3 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1435       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1436   fail_unless (pix3 == pix4);
1437
1438   /* now try to get scaled premultiplied alpha from unpremultiplied input */
1439   pix7 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1440       GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
1441   fail_if (pix7 == pix1 || pix7 == pix2 || pix7 == pix3 || pix7 == pix5);
1442
1443   gst_buffer_map (pix7, &map, GST_MAP_READ);
1444   data7 = map.data;
1445   /* make sure it actually did what we expected it to do (input=0x80808080)
1446    * hoping that the scaling didn't mess up our values */
1447 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1448   /* B - G - R - A */
1449   fail_unless_equals_int (data7[0], 0x40);
1450   fail_unless_equals_int (data7[1], 0x40);
1451   fail_unless_equals_int (data7[2], 0x40);
1452   fail_unless_equals_int (data7[3], 0x80);
1453 #else
1454   /* A - R - G - B */
1455   fail_unless_equals_int (data7[0], 0x80);
1456   fail_unless_equals_int (data7[1], 0x40);
1457   fail_unless_equals_int (data7[2], 0x40);
1458   fail_unless_equals_int (data7[3], 0x40);
1459 #endif
1460   gst_buffer_unmap (pix7, &map);
1461
1462   /* and the same again, it should be cached now */
1463   pix8 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1464       GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
1465   fail_unless (pix8 == pix7);
1466
1467   /* make sure other cached stuff is still there */
1468   pix9 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1469       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1470   fail_unless (pix9 == pix3);
1471   pix10 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1472       GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
1473   fail_unless (pix10 == pix5);
1474
1475   gst_video_overlay_rectangle_unref (rect1);
1476 }
1477
1478 GST_END_TEST;
1479
1480 GST_START_TEST (test_overlay_composition_global_alpha)
1481 {
1482   GstVideoOverlayRectangle *rect1;
1483   GstBuffer *pix1, *pix2, *pix3, *pix4, *pix5;
1484   GstVideoMeta *vmeta;
1485   guint8 *data2, *data4, *data5;
1486   guint w, h, w4, h4;
1487   guint seq1, seq2;
1488   gfloat ga1, ga2;
1489   GstVideoOverlayFormatFlags flags1;
1490   GstMapInfo map;
1491
1492   pix1 = gst_buffer_new_and_alloc (200 * sizeof (guint32) * 50);
1493   gst_buffer_memset (pix1, 0, 0x80, gst_buffer_get_size (pix1));
1494
1495   gst_buffer_add_video_meta (pix1, GST_VIDEO_FRAME_FLAG_NONE,
1496       GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB, 200, 50);
1497   rect1 = gst_video_overlay_rectangle_new_raw (pix1,
1498       600, 50, 300, 50, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1499   gst_buffer_unref (pix1);
1500
1501   /* same flags, unscaled, should be the same buffer */
1502   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1503       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1504   fail_unless (pix1 == pix2);
1505
1506   vmeta = gst_buffer_get_video_meta (pix2);
1507   fail_unless (vmeta != NULL);
1508   w = vmeta->width;
1509   h = vmeta->height;
1510
1511   /* same flags, but scaled */
1512   pix3 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1513       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1514   fail_if (pix3 == pix1 || pix3 == pix2);
1515
1516   /* get unscaled premultiplied data, new cached rectangle should be created */
1517   pix4 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1518       GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
1519   fail_if (pix4 == pix2 || pix4 == pix3);
1520   vmeta = gst_buffer_get_video_meta (pix4);
1521   fail_unless (vmeta != NULL);
1522   w4 = vmeta->width;
1523   h4 = vmeta->height;
1524   fail_unless_equals_int (w, w4);
1525   fail_unless_equals_int (h, h4);
1526   fail_unless_equals_int (gst_buffer_get_size (pix2),
1527       gst_buffer_get_size (pix4));
1528   gst_buffer_map (pix4, &map, GST_MAP_READ);
1529   fail_if (gst_buffer_memcmp (pix1, 0, map.data, map.size) == 0);
1530   /* make sure it actually did what we expected it to do (input=0x80808080) */
1531   data4 = map.data;
1532 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1533   /* B - G - R - A */
1534   fail_unless_equals_int (data4[0], 0x40);
1535   fail_unless_equals_int (data4[1], 0x40);
1536   fail_unless_equals_int (data4[2], 0x40);
1537   fail_unless_equals_int (data4[3], 0x80);
1538 #else
1539   /* A - R - G - B */
1540   fail_unless_equals_int (data4[0], 0x80);
1541   fail_unless_equals_int (data4[1], 0x40);
1542   fail_unless_equals_int (data4[2], 0x40);
1543   fail_unless_equals_int (data4[3], 0x40);
1544 #endif
1545   gst_buffer_unmap (pix4, &map);
1546
1547   /* now premultiplied and scaled, again a new cached rectangle should be cached */
1548   pix5 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1549       GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
1550   fail_if (pix5 == pix2 || pix5 == pix3 || pix5 == pix4);
1551   /* stride and size should be equal to the first scaled rect */
1552   fail_unless_equals_int (gst_buffer_get_size (pix5),
1553       gst_buffer_get_size (pix3));
1554   /* data should be different (premutliplied) though */
1555   gst_buffer_map (pix5, &map, GST_MAP_READ);
1556   fail_if (gst_buffer_memcmp (pix3, 0, map.data, map.size) == 0);
1557   /* make sure it actually did what we expected it to do (input=0x80808080) */
1558   data5 = map.data;
1559 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1560   /* B - G - R - A */
1561   fail_unless_equals_int (data5[0], 0x40);
1562   fail_unless_equals_int (data5[1], 0x40);
1563   fail_unless_equals_int (data5[2], 0x40);
1564   fail_unless_equals_int (data5[3], 0x80);
1565 #else
1566   /* A - R - G - B */
1567   fail_unless_equals_int (data5[0], 0x80);
1568   fail_unless_equals_int (data5[1], 0x40);
1569   fail_unless_equals_int (data5[2], 0x40);
1570   fail_unless_equals_int (data5[3], 0x40);
1571 #endif
1572   gst_buffer_unmap (pix5, &map);
1573
1574   /* global_alpha should initially be 1.0 */
1575   ga1 = gst_video_overlay_rectangle_get_global_alpha (rect1);
1576   fail_unless_equals_float (ga1, 1.0);
1577
1578   /* now set global_alpha */
1579   seq1 = gst_video_overlay_rectangle_get_seqnum (rect1);
1580   gst_video_overlay_rectangle_set_global_alpha (rect1, 0.5);
1581   ga2 = gst_video_overlay_rectangle_get_global_alpha (rect1);
1582   fail_unless_equals_float (ga2, 0.5);
1583
1584   /* seqnum should have changed */
1585   seq2 = gst_video_overlay_rectangle_get_seqnum (rect1);
1586   fail_unless (seq1 < seq2);
1587
1588   /* internal flags should have been set */
1589   flags1 = gst_video_overlay_rectangle_get_flags (rect1);
1590   fail_unless_equals_int (flags1, GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA);
1591
1592   /* request unscaled pixel-data, global-alpha not applied */
1593   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1594       GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA);
1595   /* this should just return the same buffer */
1596   fail_unless (pix2 == pix1);
1597   /* make sure we got the initial data (input=0x80808080) */
1598   gst_buffer_map (pix2, &map, GST_MAP_READ);
1599   data2 = map.data;
1600 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1601   /* B - G - R - A */
1602   fail_unless_equals_int (data2[0], 0x80);
1603   fail_unless_equals_int (data2[1], 0x80);
1604   fail_unless_equals_int (data2[2], 0x80);
1605   fail_unless_equals_int (data2[3], 0x80);
1606 #else
1607   /* A - R - G - B */
1608   fail_unless_equals_int (data2[0], 0x80);
1609   fail_unless_equals_int (data2[1], 0x80);
1610   fail_unless_equals_int (data2[2], 0x80);
1611   fail_unless_equals_int (data2[3], 0x80);
1612 #endif
1613   gst_buffer_unmap (pix2, &map);
1614
1615   /* unscaled pixel-data, global-alpha applied */
1616   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1617       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1618   /* this should be the same buffer with on-the-fly modified alpha-channel */
1619   fail_unless (pix2 == pix1);
1620   gst_buffer_map (pix2, &map, GST_MAP_READ);
1621   data2 = map.data;
1622   /* make sure we got the initial data with adjusted alpha-channel */
1623 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1624   /* B - G - R - A */
1625   fail_unless_equals_int (data2[0], 0x80);
1626   fail_unless_equals_int (data2[1], 0x80);
1627   fail_unless_equals_int (data2[2], 0x80);
1628   fail_unless_equals_int (data2[3], 0x40);
1629 #else
1630   /* A - R - G - B */
1631   fail_unless_equals_int (data2[0], 0x40);
1632   fail_unless_equals_int (data2[1], 0x80);
1633   fail_unless_equals_int (data2[2], 0x80);
1634   fail_unless_equals_int (data2[3], 0x80);
1635 #endif
1636   gst_buffer_unmap (pix2, &map);
1637
1638   /* adjust global_alpha once more */
1639   gst_video_overlay_rectangle_set_global_alpha (rect1, 0.25);
1640   ga2 = gst_video_overlay_rectangle_get_global_alpha (rect1);
1641   fail_unless_equals_float (ga2, 0.25);
1642   /* and again request unscaled pixel-data, global-alpha applied */
1643   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1644       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1645   fail_unless (pix2 == pix1);
1646   /* make sure we got the initial data with adjusted alpha-channel */
1647   gst_buffer_map (pix2, &map, GST_MAP_READ);
1648   data2 = map.data;
1649 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1650   /* B - G - R - A */
1651   fail_unless_equals_int (data2[0], 0x80);
1652   fail_unless_equals_int (data2[1], 0x80);
1653   fail_unless_equals_int (data2[2], 0x80);
1654   fail_unless_equals_int (data2[3], 0x20);
1655 #else
1656   /* A - R - G - B */
1657   fail_unless_equals_int (data2[0], 0x20);
1658   fail_unless_equals_int (data2[1], 0x80);
1659   fail_unless_equals_int (data2[2], 0x80);
1660   fail_unless_equals_int (data2[3], 0x80);
1661 #endif
1662   gst_buffer_unmap (pix2, &map);
1663
1664   /* again: unscaled pixel-data, global-alpha not applied,
1665    * this should revert alpha-channel to initial values */
1666   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1667       GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA);
1668   fail_unless (pix2 == pix1);
1669   /* make sure we got the initial data (input=0x80808080) */
1670   gst_buffer_map (pix2, &map, GST_MAP_READ);
1671   data2 = map.data;
1672 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1673   /* B - G - R - A */
1674   fail_unless_equals_int (data2[0], 0x80);
1675   fail_unless_equals_int (data2[1], 0x80);
1676   fail_unless_equals_int (data2[2], 0x80);
1677   fail_unless_equals_int (data2[3], 0x80);
1678 #else
1679   /* A - R - G - B */
1680   fail_unless_equals_int (data2[0], 0x80);
1681   fail_unless_equals_int (data2[1], 0x80);
1682   fail_unless_equals_int (data2[2], 0x80);
1683   fail_unless_equals_int (data2[3], 0x80);
1684 #endif
1685   gst_buffer_unmap (pix2, &map);
1686
1687   /* now scaled, global-alpha not applied */
1688   pix2 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1689       GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA);
1690   /* this should just return the rect/buffer, that was cached for these
1691    * scaling dimensions */
1692   fail_unless (pix2 == pix3);
1693   /* make sure we got the initial data (input=0x80808080) */
1694   gst_buffer_map (pix2, &map, GST_MAP_READ);
1695   data2 = map.data;
1696 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1697   /* B - G - R - A */
1698   fail_unless_equals_int (data2[0], 0x80);
1699   fail_unless_equals_int (data2[1], 0x80);
1700   fail_unless_equals_int (data2[2], 0x80);
1701   fail_unless_equals_int (data2[3], 0x80);
1702 #else
1703   /* A - R - G - B */
1704   fail_unless_equals_int (data2[0], 0x80);
1705   fail_unless_equals_int (data2[1], 0x80);
1706   fail_unless_equals_int (data2[2], 0x80);
1707   fail_unless_equals_int (data2[3], 0x80);
1708 #endif
1709   gst_buffer_unmap (pix2, &map);
1710
1711   /* scaled, global-alpha (0.25) applied */
1712   pix2 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1713       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1714   /* this should just return the rect/buffer, that was cached for these
1715    * scaling dimensions with modified alpha channel */
1716   fail_unless (pix2 == pix3);
1717   /* make sure we got the data we expect for global-alpha=0.25 */
1718   gst_buffer_map (pix2, &map, GST_MAP_READ);
1719   data2 = map.data;
1720 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1721   /* B - G - R - A */
1722   fail_unless_equals_int (data2[0], 0x80);
1723   fail_unless_equals_int (data2[1], 0x80);
1724   fail_unless_equals_int (data2[2], 0x80);
1725   fail_unless_equals_int (data2[3], 0x20);
1726 #else
1727   /* A - R - G - B */
1728   fail_unless_equals_int (data2[0], 0x20);
1729   fail_unless_equals_int (data2[1], 0x80);
1730   fail_unless_equals_int (data2[2], 0x80);
1731   fail_unless_equals_int (data2[3], 0x80);
1732 #endif
1733   gst_buffer_unmap (pix2, &map);
1734
1735   /* now unscaled premultiplied data, global-alpha not applied,
1736    * is this really a valid use case?*/
1737   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1738       GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA |
1739       GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA);
1740   /* this should just return the rect/buffer, that was cached for the
1741    * premultiplied data */
1742   fail_unless (pix2 == pix4);
1743   /* make sure we got what we expected */
1744   gst_buffer_map (pix2, &map, GST_MAP_READ);
1745   data2 = map.data;
1746 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1747   /* B - G - R - A */
1748   fail_unless_equals_int (data2[0], 0x40);
1749   fail_unless_equals_int (data2[1], 0x40);
1750   fail_unless_equals_int (data2[2], 0x40);
1751   fail_unless_equals_int (data2[3], 0x80);
1752 #else
1753   /* A - R - G - B */
1754   fail_unless_equals_int (data2[0], 0x80);
1755   fail_unless_equals_int (data2[1], 0x40);
1756   fail_unless_equals_int (data2[2], 0x40);
1757   fail_unless_equals_int (data2[3], 0x40);
1758 #endif
1759   gst_buffer_unmap (pix2, &map);
1760
1761   /* unscaled premultiplied data, global-alpha (0.25) applied */
1762   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1763       GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
1764   /* this should just return the rect/buffer, that was cached for the
1765    * premultiplied data */
1766   fail_unless (pix2 == pix4);
1767   /* make sure we got what we expected:
1768    * (0x40 / (0x80/0xFF) * (0x20/0xFF) = 0x10
1769    * NOTE: unless we are using round() for the premultiplied case
1770    * in gst_video_overlay_rectangle_apply_global_alpha() we get rounding
1771    * error, i.e. 0x0F here */
1772   gst_buffer_map (pix2, &map, GST_MAP_READ);
1773   data2 = map.data;
1774 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1775   /* B - G - R - A */
1776   fail_unless_equals_int (data2[0], 0x0F);
1777   fail_unless_equals_int (data2[1], 0x0F);
1778   fail_unless_equals_int (data2[2], 0x0F);
1779   fail_unless_equals_int (data2[3], 0x20);
1780 #else
1781   /* A - R - G - B */
1782   fail_unless_equals_int (data2[0], 0x20);
1783   fail_unless_equals_int (data2[1], 0x0F);
1784   fail_unless_equals_int (data2[2], 0x0F);
1785   fail_unless_equals_int (data2[3], 0x0F);
1786 #endif
1787   gst_buffer_unmap (pix2, &map);
1788
1789   /* set global_alpha once more */
1790   gst_video_overlay_rectangle_set_global_alpha (rect1, 0.75);
1791   /* and verify that also premultiplied data is adjusted
1792    * correspondingly (though with increasing rounding errors) */
1793   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect1,
1794       GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
1795   /* this should just return the rect/buffer, that was cached for the
1796    * premultiplied data */
1797   fail_unless (pix2 == pix4);
1798   /* make sure we got what we expected:
1799    * (0x0F / (0x20/0xFF) * (0x60/0xFF) = 0x2D
1800    * NOTE: using floats everywhere we would get 0x30
1801    * here we will actually end up with 0x2C */
1802   gst_buffer_map (pix2, &map, GST_MAP_READ);
1803   data2 = map.data;
1804 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1805   /* B - G - R - A */
1806   fail_unless_equals_int (data2[0], 0x2C);
1807   fail_unless_equals_int (data2[1], 0x2C);
1808   fail_unless_equals_int (data2[2], 0x2C);
1809   fail_unless_equals_int (data2[3], 0x60);
1810 #else
1811   /* A - R - G - B */
1812   fail_unless_equals_int (data2[0], 0x60);
1813   fail_unless_equals_int (data2[1], 0x2C);
1814   fail_unless_equals_int (data2[2], 0x2C);
1815   fail_unless_equals_int (data2[3], 0x2C);
1816 #endif
1817   gst_buffer_unmap (pix2, &map);
1818
1819   /* now scaled and premultiplied data, global-alpha not applied,
1820    * is this really a valid use case?*/
1821   pix2 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1822       GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA |
1823       GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA);
1824   /* this should just return the rect/buffer, that was cached for the
1825    * first premultiplied+scaled rect*/
1826   fail_unless (pix2 == pix5);
1827   /* make sure we got what we expected */
1828   gst_buffer_map (pix2, &map, GST_MAP_READ);
1829   data2 = map.data;
1830 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1831   /* B - G - R - A */
1832   fail_unless_equals_int (data2[0], 0x40);
1833   fail_unless_equals_int (data2[1], 0x40);
1834   fail_unless_equals_int (data2[2], 0x40);
1835   fail_unless_equals_int (data2[3], 0x80);
1836 #else
1837   /* A - R - G - B */
1838   fail_unless_equals_int (data2[0], 0x80);
1839   fail_unless_equals_int (data2[1], 0x40);
1840   fail_unless_equals_int (data2[2], 0x40);
1841   fail_unless_equals_int (data2[3], 0x40);
1842 #endif
1843   gst_buffer_unmap (pix2, &map);
1844
1845   /* scaled and premultiplied data, global-alpha applied */
1846   pix2 = gst_video_overlay_rectangle_get_pixels_raw (rect1,
1847       GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
1848   /* this should just return the rect/buffer, that was cached for the
1849    * first premultiplied+scaled rect*/
1850   fail_unless (pix2 == pix5);
1851   /* make sure we got what we expected; see above note about rounding errors! */
1852   gst_buffer_map (pix2, &map, GST_MAP_READ);
1853   data2 = map.data;
1854 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1855   /* B - G - R - A */
1856   fail_unless_equals_int (data2[0], 0x2F);
1857   fail_unless_equals_int (data2[1], 0x2F);
1858   fail_unless_equals_int (data2[2], 0x2F);
1859   fail_unless_equals_int (data2[3], 0x60);
1860 #else
1861   /* A - R - G - B */
1862   fail_unless_equals_int (data2[0], 0x60);
1863   fail_unless_equals_int (data2[1], 0x2F);
1864   fail_unless_equals_int (data2[2], 0x2F);
1865   fail_unless_equals_int (data2[3], 0x2F);
1866 #endif
1867   gst_buffer_unmap (pix2, &map);
1868
1869   gst_video_overlay_rectangle_unref (rect1);
1870 }
1871
1872 GST_END_TEST;
1873
1874 static guint8 *
1875 make_pixels (gint depth, gint width, gint height)
1876 {
1877   guint32 color = 0xff000000;
1878   gint i, j;
1879
1880   if (depth == 8) {
1881     guint8 *pixels = g_malloc (width * height * 4);
1882     for (i = 0; i < height; i++) {
1883       for (j = 0; j < width; j++) {
1884         pixels[(i * width + j) * 4 + 0] = ((color >> 24) & 0xff);
1885         pixels[(i * width + j) * 4 + 1] = ((color >> 16) & 0xff);
1886         pixels[(i * width + j) * 4 + 2] = ((color >> 8) & 0xff);
1887         pixels[(i * width + j) * 4 + 3] = (color & 0xff);
1888         color++;
1889       }
1890     }
1891     return pixels;
1892   } else {
1893 #define TO16(a) (((a)<<8)|(a))
1894     guint16 *pixels = g_malloc (width * height * 8);
1895     for (i = 0; i < height; i++) {
1896       for (j = 0; j < width; j++) {
1897         pixels[(i * width + j) * 4 + 0] = TO16 ((color >> 24) & 0xff);
1898         pixels[(i * width + j) * 4 + 1] = TO16 ((color >> 16) & 0xff);
1899         pixels[(i * width + j) * 4 + 2] = TO16 ((color >> 8) & 0xff);
1900         pixels[(i * width + j) * 4 + 3] = TO16 (color & 0xff);
1901         color++;
1902       }
1903     }
1904 #undef TO16
1905     return (guint8 *) pixels;
1906   }
1907 }
1908
1909 #define HS(x,o) ((x)&hs[o])
1910 #define WS(x,o) ((x)&ws[o])
1911 #define IN(i,j,o) (in[(HS(i, o)*width + WS(j,o))*4+(o)] & mask[o])
1912 #define OUT(i,j,o) (out[((i)*width + (j))*4+o] & mask[o])
1913 static gint
1914 compare_frame (const GstVideoFormatInfo * finfo, gint depth, guint8 * outpixels,
1915     guint8 * pixels, gint width, gint height)
1916 {
1917   gint diff, i, j, k;
1918   guint ws[4], hs[4], mask[4];
1919
1920   for (k = 0; k < 4; k++) {
1921     hs[k] = G_MAXUINT << finfo->h_sub[(3 + k) % 4];
1922     ws[k] = G_MAXUINT << finfo->w_sub[(3 + k) % 4];
1923     mask[k] = G_MAXUINT << (depth - finfo->depth[(3 + k) % 4]);
1924   }
1925   diff = 0;
1926   if (depth == 8) {
1927     guint8 *in = pixels;
1928     guint8 *out = outpixels;
1929
1930     for (i = 0; i < height; i++) {
1931       for (j = 0; j < width; j++) {
1932         for (k = 0; k < 4; k++) {
1933           diff += IN (i, j, k) != OUT (i, j, k);
1934         }
1935       }
1936     }
1937   } else {
1938     guint16 *in = (guint16 *) pixels;
1939     guint16 *out = (guint16 *) outpixels;
1940
1941     for (i = 0; i < height; i++) {
1942       for (j = 0; j < width; j++) {
1943         for (k = 0; k < 4; k++) {
1944           diff += IN (i, j, k) != OUT (i, j, k);
1945         }
1946       }
1947     }
1948   }
1949   return diff;
1950 }
1951
1952 #undef WS
1953 #undef HS
1954 #undef IN
1955 #undef OUT
1956
1957 typedef struct
1958 {
1959   GstVideoFormat infmt;
1960   GstVideoFormat outfmt;
1961   gint method;
1962   gdouble convert_sec;
1963 } ConvertResult;
1964
1965 #define SIGN(a,b) ((a) < (b) ? -1 : (a) > (b) ? 1 : 0)
1966
1967 static gint
1968 compare_result (gconstpointer a, gconstpointer b)
1969 {
1970   const ConvertResult *ap = a;
1971   const ConvertResult *bp = b;
1972
1973   return SIGN (ap->convert_sec, bp->convert_sec);
1974 }
1975
1976 #define UNPACK_FRAME(frame,dest,line,x,width)            \
1977   (frame)->info.finfo->unpack_func ((frame)->info.finfo, \
1978       (GST_VIDEO_FRAME_IS_INTERLACED (frame) ?           \
1979         GST_VIDEO_PACK_FLAG_INTERLACED :                 \
1980         GST_VIDEO_PACK_FLAG_NONE),                       \
1981       dest, (frame)->data, (frame)->info.stride, x,      \
1982       line, width)
1983 #define PACK_FRAME(frame,src,line,width)               \
1984   (frame)->info.finfo->pack_func ((frame)->info.finfo, \
1985       (GST_VIDEO_FRAME_IS_INTERLACED (frame) ?         \
1986         GST_VIDEO_PACK_FLAG_INTERLACED :               \
1987         GST_VIDEO_PACK_FLAG_NONE),                     \
1988       src, 0, (frame)->data, (frame)->info.stride,     \
1989       (frame)->info.chroma_site, line, width);
1990
1991 GST_START_TEST (test_video_pack_unpack2)
1992 {
1993   GstVideoFormat format;
1994   GTimer *timer;
1995   gint num_formats, i;
1996   GArray *packarray, *unpackarray;
1997
1998 #define WIDTH 320
1999 #define HEIGHT 240
2000 /* set to something larger to do benchmarks */
2001 #define TIME 0.01
2002
2003   timer = g_timer_new ();
2004   packarray = g_array_new (FALSE, FALSE, sizeof (ConvertResult));
2005   unpackarray = g_array_new (FALSE, FALSE, sizeof (ConvertResult));
2006
2007   num_formats = get_num_formats ();
2008
2009   GST_DEBUG ("pack/sec\t unpack/sec \tpack GB/sec\tunpack GB/sec\tformat");
2010
2011   for (format = GST_VIDEO_FORMAT_I420; format < num_formats; format++) {
2012     GstVideoInfo info;
2013     const GstVideoFormatInfo *finfo, *fuinfo;
2014     GstBuffer *buffer;
2015     GstVideoFrame frame;
2016     gint k, stride, count, diff, depth;
2017     guint8 *pixels, *outpixels;
2018     gdouble elapsed;
2019     gdouble unpack_sec, pack_sec;
2020     ConvertResult res;
2021
2022     finfo = gst_video_format_get_info (format);
2023     fail_unless (finfo != NULL);
2024
2025     if (GST_VIDEO_FORMAT_INFO_HAS_PALETTE (finfo))
2026       continue;
2027
2028     fuinfo = gst_video_format_get_info (finfo->unpack_format);
2029     fail_unless (fuinfo != NULL);
2030
2031     depth = GST_VIDEO_FORMAT_INFO_BITS (fuinfo);
2032     fail_unless (depth == 8 || depth == 16);
2033
2034     pixels = make_pixels (depth, WIDTH, HEIGHT);
2035     stride = WIDTH * (depth >> 1);
2036
2037     gst_video_info_set_format (&info, format, WIDTH, HEIGHT);
2038     buffer = gst_buffer_new_and_alloc (info.size);
2039     gst_video_frame_map (&frame, &info, buffer, GST_MAP_READWRITE);
2040
2041     /* pack the frame into the target format */
2042     /* warmup */
2043     PACK_FRAME (&frame, pixels, 0, WIDTH);
2044
2045     count = 0;
2046     g_timer_start (timer);
2047     while (TRUE) {
2048       for (k = 0; k < HEIGHT; k += finfo->pack_lines) {
2049         PACK_FRAME (&frame, pixels + k * stride, k, WIDTH);
2050       }
2051       count++;
2052       elapsed = g_timer_elapsed (timer, NULL);
2053       if (elapsed >= TIME)
2054         break;
2055     }
2056     unpack_sec = count / elapsed;
2057
2058     res.infmt = format;
2059     res.outfmt = finfo->unpack_format;
2060     res.convert_sec = unpack_sec;
2061     g_array_append_val (unpackarray, res);
2062
2063     outpixels = g_malloc0 (HEIGHT * stride);
2064
2065     /* unpack the frame */
2066     /* warmup */
2067     UNPACK_FRAME (&frame, outpixels, 0, 0, WIDTH);
2068
2069     count = 0;
2070     g_timer_start (timer);
2071     while (TRUE) {
2072       for (k = 0; k < HEIGHT; k += finfo->pack_lines) {
2073         UNPACK_FRAME (&frame, outpixels + k * stride, k, 0, WIDTH);
2074       }
2075       count++;
2076       elapsed = g_timer_elapsed (timer, NULL);
2077       if (elapsed >= TIME)
2078         break;
2079     }
2080     pack_sec = count / elapsed;
2081
2082     res.outfmt = format;
2083     res.infmt = finfo->unpack_format;
2084     res.convert_sec = pack_sec;
2085     g_array_append_val (packarray, res);
2086
2087     /* compare the frame */
2088     diff = compare_frame (finfo, depth, outpixels, pixels, WIDTH, HEIGHT);
2089
2090     GST_DEBUG ("%f \t %f \t %f \t %f \t %s %d/%f", pack_sec, unpack_sec,
2091         info.size * pack_sec, info.size * unpack_sec, finfo->name, count,
2092         elapsed);
2093
2094     if (diff != 0) {
2095       gst_util_dump_mem (outpixels, 128);
2096       gst_util_dump_mem (pixels, 128);
2097       fail_if (diff != 0);
2098     }
2099     gst_video_frame_unmap (&frame);
2100     gst_buffer_unref (buffer);
2101     g_free (pixels);
2102     g_free (outpixels);
2103   }
2104
2105   g_array_sort (packarray, compare_result);
2106   for (i = 0; i < packarray->len; i++) {
2107     ConvertResult *res = &g_array_index (packarray, ConvertResult, i);
2108
2109     GST_DEBUG ("%f pack/sec %s->%s", res->convert_sec,
2110         gst_video_format_to_string (res->infmt),
2111         gst_video_format_to_string (res->outfmt));
2112   }
2113
2114   g_array_sort (unpackarray, compare_result);
2115   for (i = 0; i < unpackarray->len; i++) {
2116     ConvertResult *res = &g_array_index (unpackarray, ConvertResult, i);
2117
2118     GST_DEBUG ("%f unpack/sec %s->%s", res->convert_sec,
2119         gst_video_format_to_string (res->infmt),
2120         gst_video_format_to_string (res->outfmt));
2121   }
2122
2123   g_timer_destroy (timer);
2124   g_array_free (packarray, TRUE);
2125   g_array_free (unpackarray, TRUE);
2126 }
2127
2128 GST_END_TEST;
2129 #undef WIDTH
2130 #undef HEIGHT
2131 #undef TIME
2132
2133 #define WIDTH 320
2134 #define HEIGHT 240
2135 #define TIME 0.1
2136 #define GET_LINE(l) (pixels + CLAMP (l, 0, HEIGHT-1) * WIDTH * 4)
2137 GST_START_TEST (test_video_chroma)
2138 {
2139   guint8 *pixels;
2140   guint n_lines;
2141   gint i, j, k, offset, count;
2142   gpointer lines[10];
2143   GTimer *timer;
2144   gdouble elapsed, subsample_sec;
2145   GstVideoChromaSite sites[] = {
2146     GST_VIDEO_CHROMA_SITE_NONE,
2147     GST_VIDEO_CHROMA_SITE_H_COSITED,
2148   };
2149
2150   timer = g_timer_new ();
2151   pixels = make_pixels (8, WIDTH, HEIGHT);
2152
2153   for (k = 0; k < G_N_ELEMENTS (sites); k++) {
2154     GstVideoChromaResample *resample;
2155
2156     resample = gst_video_chroma_resample_new (GST_VIDEO_CHROMA_METHOD_LINEAR,
2157         sites[k], GST_VIDEO_CHROMA_FLAG_NONE, GST_VIDEO_FORMAT_AYUV, -1, -1);
2158
2159     gst_video_chroma_resample_get_info (resample, &n_lines, &offset);
2160     fail_unless (n_lines < 10);
2161
2162     /* warmup */
2163     for (j = 0; j < n_lines; j++)
2164       lines[j] = GET_LINE (offset + j);
2165     gst_video_chroma_resample (resample, lines, WIDTH);
2166
2167     count = 0;
2168     g_timer_start (timer);
2169     while (TRUE) {
2170       for (i = 0; i < HEIGHT; i += n_lines) {
2171         for (j = 0; j < n_lines; j++)
2172           lines[j] = GET_LINE (i + offset + j);
2173
2174         gst_video_chroma_resample (resample, lines, WIDTH);
2175       }
2176       count++;
2177       elapsed = g_timer_elapsed (timer, NULL);
2178       if (elapsed >= TIME)
2179         break;
2180     }
2181     subsample_sec = count / elapsed;
2182     GST_DEBUG ("%f downsamples/sec  %d/%f", subsample_sec, count, elapsed);
2183     gst_video_chroma_resample_free (resample);
2184
2185     resample = gst_video_chroma_resample_new (GST_VIDEO_CHROMA_METHOD_LINEAR,
2186         sites[k], GST_VIDEO_CHROMA_FLAG_NONE, GST_VIDEO_FORMAT_AYUV, 1, 1);
2187
2188     gst_video_chroma_resample_get_info (resample, &n_lines, &offset);
2189     fail_unless (n_lines < 10);
2190
2191     /* warmup */
2192     for (j = 0; j < n_lines; j++)
2193       lines[j] = GET_LINE (offset + j);
2194     gst_video_chroma_resample (resample, lines, WIDTH);
2195
2196     count = 0;
2197     g_timer_start (timer);
2198     while (TRUE) {
2199       for (i = 0; i < HEIGHT; i += n_lines) {
2200         for (j = 0; j < n_lines; j++)
2201           lines[j] = GET_LINE (i + offset + j);
2202
2203         gst_video_chroma_resample (resample, lines, WIDTH);
2204       }
2205       count++;
2206       elapsed = g_timer_elapsed (timer, NULL);
2207       if (elapsed >= TIME)
2208         break;
2209     }
2210     subsample_sec = count / elapsed;
2211     GST_DEBUG ("%f upsamples/sec  %d/%f", subsample_sec, count, elapsed);
2212     gst_video_chroma_resample_free (resample);
2213   }
2214
2215   g_free (pixels);
2216   g_timer_destroy (timer);
2217 }
2218
2219 GST_END_TEST;
2220 #undef WIDTH
2221 #undef HEIGHT
2222 #undef TIME
2223
2224 GST_START_TEST (test_video_scaler)
2225 {
2226   GstVideoScaler *scale;
2227
2228   scale = gst_video_scaler_new (GST_VIDEO_RESAMPLER_METHOD_LINEAR,
2229       GST_VIDEO_SCALER_FLAG_NONE, 2, 10, 5, NULL);
2230   gst_video_scaler_free (scale);
2231
2232   scale = gst_video_scaler_new (GST_VIDEO_RESAMPLER_METHOD_LINEAR,
2233       GST_VIDEO_SCALER_FLAG_NONE, 2, 15, 5, NULL);
2234   gst_video_scaler_free (scale);
2235 }
2236
2237 GST_END_TEST;
2238
2239 #define WIDTH 320
2240 #define HEIGHT 240
2241 #define TIME 0.01
2242
2243 GST_START_TEST (test_video_color_convert)
2244 {
2245   GstVideoFormat infmt, outfmt;
2246   GTimer *timer;
2247   gint num_formats, i;
2248   GArray *array;
2249
2250   array = g_array_new (FALSE, FALSE, sizeof (ConvertResult));
2251
2252   timer = g_timer_new ();
2253
2254   num_formats = get_num_formats ();
2255
2256   for (infmt = GST_VIDEO_FORMAT_I420; infmt < num_formats; infmt++) {
2257     GstVideoInfo ininfo;
2258     GstVideoFrame inframe;
2259     GstBuffer *inbuffer;
2260
2261     gst_video_info_set_format (&ininfo, infmt, WIDTH, HEIGHT);
2262     inbuffer = gst_buffer_new_and_alloc (ininfo.size);
2263     gst_buffer_memset (inbuffer, 0, 0, -1);
2264     gst_video_frame_map (&inframe, &ininfo, inbuffer, GST_MAP_READ);
2265
2266     for (outfmt = GST_VIDEO_FORMAT_I420; outfmt < num_formats; outfmt++) {
2267       GstVideoInfo outinfo;
2268       GstVideoFrame outframe;
2269       GstBuffer *outbuffer;
2270       GstVideoConverter *convert;
2271       gdouble elapsed;
2272       gint count;
2273       ConvertResult res;
2274
2275       gst_video_info_set_format (&outinfo, outfmt, WIDTH, HEIGHT);
2276       outbuffer = gst_buffer_new_and_alloc (outinfo.size);
2277       gst_video_frame_map (&outframe, &outinfo, outbuffer, GST_MAP_WRITE);
2278
2279       convert = gst_video_converter_new (&ininfo, &outinfo, NULL);
2280       /* warmup */
2281       gst_video_converter_frame (convert, &inframe, &outframe);
2282
2283       count = 0;
2284       g_timer_start (timer);
2285       while (TRUE) {
2286         gst_video_converter_frame (convert, &inframe, &outframe);
2287
2288         count++;
2289         elapsed = g_timer_elapsed (timer, NULL);
2290         if (elapsed >= TIME)
2291           break;
2292       }
2293
2294       res.infmt = infmt;
2295       res.outfmt = outfmt;
2296       res.convert_sec = count / elapsed;
2297
2298       GST_DEBUG ("%f conversions/sec %s->%s, %d/%f", res.convert_sec,
2299           gst_video_format_to_string (infmt),
2300           gst_video_format_to_string (outfmt), count, elapsed);
2301
2302       g_array_append_val (array, res);
2303
2304       gst_video_converter_free (convert);
2305
2306       gst_video_frame_unmap (&outframe);
2307       gst_buffer_unref (outbuffer);
2308     }
2309     gst_video_frame_unmap (&inframe);
2310     gst_buffer_unref (inbuffer);
2311   }
2312
2313   g_array_sort (array, compare_result);
2314
2315   for (i = 0; i < array->len; i++) {
2316     ConvertResult *res = &g_array_index (array, ConvertResult, i);
2317
2318     GST_DEBUG ("%f conversions/sec %s->%s", res->convert_sec,
2319         gst_video_format_to_string (res->infmt),
2320         gst_video_format_to_string (res->outfmt));
2321   }
2322
2323   g_array_free (array, TRUE);
2324
2325   g_timer_destroy (timer);
2326 }
2327
2328 GST_END_TEST;
2329 #undef WIDTH
2330 #undef HEIGHT
2331
2332 #define WIDTH_IN 320
2333 #define HEIGHT_IN 240
2334 #define WIDTH_OUT 400
2335 #define HEIGHT_OUT 300
2336 #define TIME 0.01
2337
2338 GST_START_TEST (test_video_size_convert)
2339 {
2340   GstVideoFormat infmt, outfmt;
2341   GTimer *timer;
2342   gint num_formats, i;
2343   GArray *array;
2344
2345   array = g_array_new (FALSE, FALSE, sizeof (ConvertResult));
2346
2347   timer = g_timer_new ();
2348
2349   num_formats = get_num_formats ();
2350
2351   for (infmt = GST_VIDEO_FORMAT_I420; infmt < num_formats; infmt++) {
2352     GstVideoInfo ininfo, outinfo;
2353     GstVideoFrame inframe, outframe;
2354     GstBuffer *inbuffer, *outbuffer;
2355     GstVideoConverter *convert;
2356     gdouble elapsed;
2357     gint count, method;
2358     ConvertResult res;
2359
2360     gst_video_info_set_format (&ininfo, infmt, WIDTH_IN, HEIGHT_IN);
2361     inbuffer = gst_buffer_new_and_alloc (ininfo.size);
2362     gst_buffer_memset (inbuffer, 0, 0, -1);
2363     gst_video_frame_map (&inframe, &ininfo, inbuffer, GST_MAP_READ);
2364
2365     outfmt = infmt;
2366     gst_video_info_set_format (&outinfo, outfmt, WIDTH_OUT, HEIGHT_OUT);
2367     outbuffer = gst_buffer_new_and_alloc (outinfo.size);
2368     gst_video_frame_map (&outframe, &outinfo, outbuffer, GST_MAP_WRITE);
2369
2370     for (method = 0; method < 4; method++) {
2371       convert = gst_video_converter_new (&ininfo, &outinfo,
2372           gst_structure_new ("options",
2373               GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
2374               GST_TYPE_VIDEO_RESAMPLER_METHOD, method, NULL));
2375
2376       /* warmup */
2377       gst_video_converter_frame (convert, &inframe, &outframe);
2378
2379       count = 0;
2380       g_timer_start (timer);
2381       while (TRUE) {
2382         gst_video_converter_frame (convert, &inframe, &outframe);
2383
2384         count++;
2385         elapsed = g_timer_elapsed (timer, NULL);
2386         if (elapsed >= TIME)
2387           break;
2388       }
2389
2390       res.infmt = infmt;
2391       res.outfmt = outfmt;
2392       res.method = method;
2393       res.convert_sec = count / elapsed;
2394
2395       GST_DEBUG ("%f resize/sec %s->%s, %d, %d/%f", res.convert_sec,
2396           gst_video_format_to_string (infmt),
2397           gst_video_format_to_string (outfmt), method, count, elapsed);
2398
2399       g_array_append_val (array, res);
2400
2401       gst_video_converter_free (convert);
2402     }
2403     gst_video_frame_unmap (&outframe);
2404     gst_buffer_unref (outbuffer);
2405     gst_video_frame_unmap (&inframe);
2406     gst_buffer_unref (inbuffer);
2407   }
2408
2409   g_array_sort (array, compare_result);
2410
2411   for (i = 0; i < array->len; i++) {
2412     ConvertResult *res = &g_array_index (array, ConvertResult, i);
2413
2414     GST_DEBUG ("%f method %d, resize/sec %s->%s", res->convert_sec, res->method,
2415         gst_video_format_to_string (res->infmt),
2416         gst_video_format_to_string (res->outfmt));
2417   }
2418
2419   g_array_free (array, TRUE);
2420
2421   g_timer_destroy (timer);
2422 }
2423
2424 GST_END_TEST;
2425 #undef WIDTH
2426 #undef HEIGHT
2427
2428 GST_START_TEST (test_video_convert)
2429 {
2430   GstVideoInfo ininfo, outinfo;
2431   GstVideoFrame inframe, outframe;
2432   GstBuffer *inbuffer, *outbuffer;
2433   GstVideoConverter *convert;
2434
2435   gst_video_info_set_format (&ininfo, GST_VIDEO_FORMAT_ARGB, 320, 240);
2436   inbuffer = gst_buffer_new_and_alloc (ininfo.size);
2437   gst_buffer_memset (inbuffer, 0, 0, -1);
2438   gst_video_frame_map (&inframe, &ininfo, inbuffer, GST_MAP_READ);
2439
2440   gst_video_info_set_format (&outinfo, GST_VIDEO_FORMAT_BGRx, 400, 300);
2441   outbuffer = gst_buffer_new_and_alloc (outinfo.size);
2442   gst_video_frame_map (&outframe, &outinfo, outbuffer, GST_MAP_WRITE);
2443
2444   /* see that we don't reuse the source line directly because we need
2445    * to add borders to it */
2446   convert = gst_video_converter_new (&ininfo, &outinfo,
2447       gst_structure_new ("options",
2448           GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
2449           GST_TYPE_VIDEO_RESAMPLER_METHOD, 3,
2450           GST_VIDEO_CONVERTER_OPT_SRC_X, G_TYPE_INT, 10,
2451           GST_VIDEO_CONVERTER_OPT_SRC_Y, G_TYPE_INT, 0,
2452           GST_VIDEO_CONVERTER_OPT_SRC_WIDTH, G_TYPE_INT, 300,
2453           GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT, G_TYPE_INT, 220,
2454           GST_VIDEO_CONVERTER_OPT_DEST_X, G_TYPE_INT, 80,
2455           GST_VIDEO_CONVERTER_OPT_DEST_Y, G_TYPE_INT, 60,
2456           GST_VIDEO_CONVERTER_OPT_DEST_WIDTH, G_TYPE_INT, 300,
2457           GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT, G_TYPE_INT, 220, NULL));
2458
2459   gst_video_converter_frame (convert, &inframe, &outframe);
2460   gst_video_converter_free (convert);
2461
2462   /* see that we reuse the source line directly because we need to scale
2463    * it first */
2464   convert = gst_video_converter_new (&ininfo, &outinfo,
2465       gst_structure_new ("options",
2466           GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
2467           GST_TYPE_VIDEO_RESAMPLER_METHOD, 3,
2468           GST_VIDEO_CONVERTER_OPT_SRC_X, G_TYPE_INT, 10,
2469           GST_VIDEO_CONVERTER_OPT_SRC_Y, G_TYPE_INT, 0,
2470           GST_VIDEO_CONVERTER_OPT_SRC_WIDTH, G_TYPE_INT, 300,
2471           GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT, G_TYPE_INT, 220,
2472           GST_VIDEO_CONVERTER_OPT_DEST_X, G_TYPE_INT, 80,
2473           GST_VIDEO_CONVERTER_OPT_DEST_Y, G_TYPE_INT, 60,
2474           GST_VIDEO_CONVERTER_OPT_DEST_WIDTH, G_TYPE_INT, 310,
2475           GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT, G_TYPE_INT, 230, NULL));
2476
2477   gst_video_converter_frame (convert, &inframe, &outframe);
2478   gst_video_converter_free (convert);
2479
2480   gst_video_frame_unmap (&outframe);
2481   gst_buffer_unref (outbuffer);
2482   gst_video_frame_unmap (&inframe);
2483   gst_buffer_unref (inbuffer);
2484
2485 }
2486
2487 GST_END_TEST;
2488
2489 GST_START_TEST (test_video_transfer)
2490 {
2491   gint i, j;
2492
2493   for (j = GST_VIDEO_TRANSFER_GAMMA10; j <= GST_VIDEO_TRANSFER_LOG316; j++) {
2494     for (i = 0; i < 256; i++) {
2495       gdouble val1, val2;
2496
2497       val1 = gst_video_color_transfer_encode (j, i / 255.0);
2498       fail_if (val1 < 0.0 || val1 > 1.0);
2499
2500       val2 = gst_video_color_transfer_decode (j, val1);
2501       fail_if (val2 < 0.0 || val2 > 1.0);
2502
2503       GST_DEBUG ("%d: %d %f->%f->%f %d", j, i, i / 255.0, val1, val2,
2504           (int) lrint (val2 * 255.0));
2505       if (val1 == 0.0)
2506         fail_if (val2 != 0.0);
2507       else
2508         fail_if (lrint (val2 * 255.0) != i);
2509     }
2510   }
2511 }
2512
2513 GST_END_TEST;
2514
2515 GST_START_TEST (test_video_center_rect)
2516 {
2517   GstVideoRectangle src, dest, result, expected;
2518
2519 #define NEW_RECT(x,y,w,h) ((GstVideoRectangle) {x,y,w,h})
2520 #define CHECK_RECT(res, exp)                    \
2521   fail_unless_equals_int(exp.x, res.x);\
2522   fail_unless_equals_int(exp.y, res.y);\
2523   fail_unless_equals_int(exp.w, res.w);\
2524   fail_unless_equals_int(exp.h, res.h);
2525
2526   /* 1:1 Aspect Ratio */
2527   src = NEW_RECT (0, 0, 100, 100);
2528   dest = NEW_RECT (0, 0, 100, 100);
2529   expected = NEW_RECT (0, 0, 100, 100);
2530   gst_video_sink_center_rect (src, dest, &result, TRUE);
2531   CHECK_RECT (result, expected);
2532
2533   src = NEW_RECT (0, 0, 100, 100);
2534   dest = NEW_RECT (0, 0, 50, 50);
2535   expected = NEW_RECT (0, 0, 50, 50);
2536   gst_video_sink_center_rect (src, dest, &result, TRUE);
2537   CHECK_RECT (result, expected);
2538
2539   src = NEW_RECT (0, 0, 100, 100);
2540   dest = NEW_RECT (50, 50, 100, 100);
2541   expected = NEW_RECT (50, 50, 100, 100);
2542   gst_video_sink_center_rect (src, dest, &result, TRUE);
2543   CHECK_RECT (result, expected);
2544
2545   /* Aspect ratio scaling (tall) */
2546   src = NEW_RECT (0, 0, 50, 100);
2547   dest = NEW_RECT (0, 0, 50, 50);
2548   expected = NEW_RECT (12, 0, 25, 50);
2549   gst_video_sink_center_rect (src, dest, &result, TRUE);
2550   CHECK_RECT (result, expected);
2551
2552   src = NEW_RECT (0, 0, 50, 100);
2553   dest = NEW_RECT (50, 50, 50, 50);
2554   expected = NEW_RECT (62, 50, 25, 50);
2555   gst_video_sink_center_rect (src, dest, &result, TRUE);
2556   CHECK_RECT (result, expected);
2557
2558   /* Aspect ratio scaling (wide) */
2559   src = NEW_RECT (0, 0, 100, 50);
2560   dest = NEW_RECT (0, 0, 50, 50);
2561   expected = NEW_RECT (0, 12, 50, 25);
2562   gst_video_sink_center_rect (src, dest, &result, TRUE);
2563   CHECK_RECT (result, expected);
2564
2565   src = NEW_RECT (0, 0, 100, 50);
2566   dest = NEW_RECT (50, 50, 50, 50);
2567   expected = NEW_RECT (50, 62, 50, 25);
2568   gst_video_sink_center_rect (src, dest, &result, TRUE);
2569   CHECK_RECT (result, expected);
2570 }
2571
2572 GST_END_TEST;
2573
2574 void test_overlay_blend_rect (gint x, gint y, gint width, gint height,
2575     GstVideoFrame * video_frame);
2576 void test_overlay_blend_rect_verify (gint x, gint y, gint width,
2577     gint height, GstVideoFrame * video_frame);
2578 #define VIDEO_WIDTH 320
2579 #define VIDEO_HEIGHT 240
2580
2581 void
2582 test_overlay_blend_rect_verify (gint x, gint y, gint width, gint height,
2583     GstVideoFrame * video_frame)
2584 {
2585   guint8 *data;
2586   gint i = 0, prev_i = 0;
2587   gint size = 0;
2588   gint temp_width = 0, temp_height = 0;
2589
2590   data = GST_VIDEO_FRAME_PLANE_DATA (video_frame, 0);
2591   size = GST_VIDEO_FRAME_SIZE (video_frame);
2592
2593   if (x + width < 0 || y + height < 0 || x >= VIDEO_WIDTH || y >= VIDEO_HEIGHT)
2594     return;
2595   if (x <= 0)
2596     temp_width = width + x;
2597   else if (x > 0 && (x + width) <= VIDEO_WIDTH)
2598     temp_width = width;
2599   else
2600     temp_width = VIDEO_WIDTH - x;
2601   if (y <= 0)
2602     temp_height = height + y;
2603   else if (y > 0 && (y + height) <= VIDEO_HEIGHT)
2604     temp_height = height;
2605   else
2606     temp_height = VIDEO_HEIGHT - y;
2607
2608   if (x <= 0 && y <= 0)
2609     i = 0;
2610   else
2611     i = (((x <= 0) ? 0 : x) + (((y <= 0) ? 0 : y) * VIDEO_WIDTH)) * 4;
2612   prev_i = i;
2613
2614   for (; i < size - 4; i += 4) {
2615 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
2616     /* B - G - R - A */
2617     fail_unless_equals_int (data[i], 0x80);
2618     fail_unless_equals_int (data[i + 1], 0x80);
2619     fail_unless_equals_int (data[i + 2], 0x80);
2620     fail_unless_equals_int (data[i + 3], 0x80);
2621 #else
2622     /* A - R - G - B */
2623     fail_unless_equals_int (data[i], 0x00);
2624     fail_unless_equals_int (data[i + 1], 0x80);
2625     fail_unless_equals_int (data[i + 2], 0x80);
2626     fail_unless_equals_int (data[i + 3], 0x80);
2627 #endif
2628     if ((i + 4) == (4 * (((((y > 0) ? (y + temp_height) : temp_height) -
2629                         1) * VIDEO_WIDTH) + ((x >
2630                         0) ? (x + temp_width) : temp_width))))
2631       break;
2632     if ((i + 4 - prev_i) == ((temp_width) * 4)) {
2633       i += ((VIDEO_WIDTH - (temp_width)) * 4);
2634       prev_i = i + 4;
2635     }
2636
2637   }
2638 }
2639
2640 void
2641 test_overlay_blend_rect (gint x, gint y, gint width, gint height,
2642     GstVideoFrame * video_frame)
2643 {
2644   GstVideoOverlayComposition *comp1;
2645   GstVideoOverlayRectangle *rect1;
2646   GstBuffer *pix, *pix1;
2647   GstVideoInfo vinfo;
2648
2649   memset (video_frame, 0, sizeof (GstVideoFrame));
2650   pix =
2651       gst_buffer_new_and_alloc (VIDEO_WIDTH * VIDEO_HEIGHT * sizeof (guint32));
2652   gst_buffer_memset (pix, 0, 0, gst_buffer_get_size (pix));
2653   gst_video_info_init (&vinfo);
2654   gst_video_info_set_format (&vinfo, GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB,
2655       VIDEO_WIDTH, VIDEO_HEIGHT);
2656   gst_video_frame_map (video_frame, &vinfo, pix, GST_MAP_READWRITE);
2657   gst_buffer_unref (pix);
2658   pix = NULL;
2659
2660   pix1 = gst_buffer_new_and_alloc (width * height * sizeof (guint32));
2661   gst_buffer_memset (pix1, 0, 0x80, gst_buffer_get_size (pix1));
2662   gst_buffer_add_video_meta (pix1, GST_VIDEO_FRAME_FLAG_NONE,
2663       GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB, width, height);
2664   rect1 = gst_video_overlay_rectangle_new_raw (pix1,
2665       x, y, width, height, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
2666   gst_buffer_unref (pix1);
2667   pix1 = NULL;
2668
2669   comp1 = gst_video_overlay_composition_new (rect1);
2670   fail_unless (gst_video_overlay_composition_blend (comp1, video_frame));
2671   gst_video_overlay_composition_unref (comp1);
2672   gst_video_overlay_rectangle_unref (rect1);
2673
2674   test_overlay_blend_rect_verify (x, y, width, height, video_frame);
2675   gst_video_frame_unmap (video_frame);
2676 }
2677
2678 GST_START_TEST (test_overlay_blend)
2679 {
2680   GstVideoFrame video_frame;
2681
2682   /* Overlay width & height smaller than video width & height */
2683   /* Overlay rendered completely left of video surface
2684    * x + overlay_width <= 0 */
2685   test_overlay_blend_rect (-60, 50, 50, 50, &video_frame);
2686   /* Overlay rendered completely right of video surface
2687    * x >= video_width */
2688   test_overlay_blend_rect (330, 50, 50, 50, &video_frame);
2689   /* Overlay rendered completely top of video surface
2690    * y + overlay_height <= 0 */
2691   test_overlay_blend_rect (50, -60, 50, 50, &video_frame);
2692   /* Overlay rendered completely bottom of video surface
2693    * y >= video_height */
2694   test_overlay_blend_rect (50, 250, 50, 50, &video_frame);
2695   /* Overlay rendered partially left of video surface
2696    * x < 0 && -x < overlay_width */
2697   test_overlay_blend_rect (-40, 50, 50, 50, &video_frame);
2698   /* Overlay rendered partially right of video surface
2699    * x < video_width && (overlay_width + x) > video_width */
2700   test_overlay_blend_rect (300, 50, 50, 50, &video_frame);
2701   /* Overlay rendered partially top of video surface
2702    * y < 0 && -y < overlay_height */
2703   test_overlay_blend_rect (50, -40, 50, 50, &video_frame);
2704   /* Overlay rendered partially bottom of video surface
2705    * y < video_height && (overlay_height + y) > video_height */
2706   test_overlay_blend_rect (50, 220, 50, 50, &video_frame);
2707
2708   /* Overlay width & height bigger than video width & height */
2709   /* Overlay rendered completely left of video surface
2710    * x + overlay_width <= 0 */
2711   test_overlay_blend_rect (-360, 50, 350, 250, &video_frame);
2712   /* Overlay rendered completely right of video surface
2713    * x >= video_width */
2714   test_overlay_blend_rect (330, 50, 350, 250, &video_frame);
2715   /* Overlay rendered completely top of video surface
2716    * y + overlay_height <= 0 */
2717   test_overlay_blend_rect (50, -260, 350, 250, &video_frame);
2718   /* Overlay rendered completely bottom of video surface
2719    * y >= video_height */
2720   test_overlay_blend_rect (50, 250, 350, 250, &video_frame);
2721   /* Overlay rendered partially left of video surface
2722    * x < 0 && -x < overlay_width */
2723   test_overlay_blend_rect (-40, 50, 350, 250, &video_frame);
2724   /* Overlay rendered partially right of video surface
2725    * x < video_width && (overlay_width + x) > video_width */
2726   test_overlay_blend_rect (300, 50, 350, 250, &video_frame);
2727   /* Overlay rendered partially top of video surface
2728    * y < 0 && -y < overlay_height */
2729   test_overlay_blend_rect (50, -40, 350, 250, &video_frame);
2730   /* Overlay rendered partially bottom of video surface
2731    * y < video_height && (overlay_height + y) > video_height */
2732   test_overlay_blend_rect (50, 220, 350, 250, &video_frame);
2733 }
2734
2735 GST_END_TEST;
2736
2737 GST_START_TEST (test_overlay_composition_over_transparency)
2738 {
2739   GstVideoOverlayComposition *comp1;
2740   GstVideoOverlayRectangle *rect1;
2741   GstBuffer *pix1, *pix2;
2742   GstVideoInfo vinfo;
2743   guint8 *data;
2744
2745   GstVideoFrame video_frame;
2746   guint fwidth = 200, height = 50, swidth = 100;
2747
2748   memset (&video_frame, 0, sizeof (GstVideoFrame));
2749
2750   pix1 = gst_buffer_new_and_alloc (fwidth * sizeof (guint32) * height);
2751   gst_buffer_memset (pix1, 0, 0x00, gst_buffer_get_size (pix1));
2752   gst_video_info_init (&vinfo);
2753   gst_video_info_set_format (&vinfo, GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB,
2754       fwidth, height);
2755   gst_video_frame_map (&video_frame, &vinfo, pix1, GST_MAP_READWRITE);
2756   gst_buffer_unref (pix1);
2757
2758   pix2 = gst_buffer_new_and_alloc (swidth * sizeof (guint32) * height);
2759   gst_buffer_memset (pix2, 0, 0xFF, gst_buffer_get_size (pix2));
2760   gst_buffer_add_video_meta (pix2, GST_VIDEO_FRAME_FLAG_NONE,
2761       GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB, swidth, height);
2762   rect1 = gst_video_overlay_rectangle_new_raw (pix2, swidth, 0,
2763       swidth, height, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
2764
2765   comp1 = gst_video_overlay_composition_new (rect1);
2766   fail_unless (gst_video_overlay_composition_blend (comp1, &video_frame));
2767   gst_video_overlay_composition_unref (comp1);
2768   gst_video_overlay_rectangle_unref (rect1);
2769   gst_buffer_unref (pix2);
2770
2771   data = GST_VIDEO_FRAME_PLANE_DATA (&video_frame, 0);
2772
2773   fail_unless_equals_int (data[0], 0x00);
2774   fail_unless_equals_int (data[1], 0x00);
2775   fail_unless_equals_int (data[2], 0x00);
2776   fail_unless_equals_int (data[3], 0x00);
2777
2778   data += swidth * sizeof (guint32);
2779
2780   fail_unless_equals_int (data[0], 0xFF);
2781   fail_unless_equals_int (data[1], 0xFF);
2782   fail_unless_equals_int (data[2], 0xFF);
2783   fail_unless_equals_int (data[3], 0xFF);
2784
2785   gst_video_frame_unmap (&video_frame);
2786 }
2787
2788 GST_END_TEST;
2789
2790
2791 static Suite *
2792 video_suite (void)
2793 {
2794   Suite *s = suite_create ("video support library");
2795   TCase *tc_chain = tcase_create ("general");
2796
2797   tcase_set_timeout (tc_chain, 60 * 60);
2798
2799   suite_add_tcase (s, tc_chain);
2800   tcase_add_test (tc_chain, test_video_formats);
2801   tcase_add_test (tc_chain, test_video_formats_overflow);
2802   tcase_add_test (tc_chain, test_video_formats_rgb);
2803   tcase_add_test (tc_chain, test_video_formats_rgba_large_dimension);
2804   tcase_add_test (tc_chain, test_video_formats_all);
2805   tcase_add_test (tc_chain, test_video_formats_pack_unpack);
2806   tcase_add_test (tc_chain, test_dar_calc);
2807   tcase_add_test (tc_chain, test_parse_caps_rgb);
2808   tcase_add_test (tc_chain, test_parse_caps_multiview);
2809   tcase_add_test (tc_chain, test_parse_colorimetry);
2810   tcase_add_test (tc_chain, test_events);
2811   tcase_add_test (tc_chain, test_convert_frame);
2812   tcase_add_test (tc_chain, test_convert_frame_async);
2813   tcase_add_test (tc_chain, test_video_size_from_caps);
2814   tcase_add_test (tc_chain, test_overlay_composition);
2815   tcase_add_test (tc_chain, test_overlay_composition_premultiplied_alpha);
2816   tcase_add_test (tc_chain, test_overlay_composition_global_alpha);
2817   tcase_add_test (tc_chain, test_video_pack_unpack2);
2818   tcase_add_test (tc_chain, test_video_chroma);
2819   tcase_add_test (tc_chain, test_video_scaler);
2820   tcase_add_test (tc_chain, test_video_color_convert);
2821   tcase_add_test (tc_chain, test_video_size_convert);
2822   tcase_add_test (tc_chain, test_video_convert);
2823   tcase_add_test (tc_chain, test_video_transfer);
2824   tcase_add_test (tc_chain, test_overlay_blend);
2825   tcase_add_test (tc_chain, test_video_center_rect);
2826   tcase_add_test (tc_chain, test_overlay_composition_over_transparency);
2827
2828   return s;
2829 }
2830
2831 GST_CHECK_MAIN (video);