tizen 2.3 release
[framework/multimedia/gst-plugins-base0.10.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  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <unistd.h>
28
29 #include <gst/check/gstcheck.h>
30
31 #include <gst/video/video.h>
32 #include <gst/video/video-overlay-composition.h>
33 #include <string.h>
34
35 /* These are from the current/old videotestsrc; we check our new public API
36  * in libgstvideo against the old one to make sure the sizes and offsets
37  * end up the same */
38
39 typedef struct paintinfo_struct paintinfo;
40 struct paintinfo_struct
41 {
42   unsigned char *dest;          /* pointer to first byte of video data */
43   unsigned char *yp, *up, *vp;  /* pointers to first byte of each component
44                                  * for both packed/planar YUV and RGB */
45   unsigned char *ap;            /* pointer to first byte of alpha component */
46   unsigned char *endptr;        /* pointer to byte beyond last video data */
47   int ystride;
48   int ustride;
49   int vstride;
50   int width;
51   int height;
52 };
53
54 struct fourcc_list_struct
55 {
56   const char *fourcc;
57   const char *name;
58   int bitspp;
59   void (*paint_setup) (paintinfo * p, unsigned char *dest);
60 };
61
62 static void paint_setup_I420 (paintinfo * p, unsigned char *dest);
63 static void paint_setup_YV12 (paintinfo * p, unsigned char *dest);
64 static void paint_setup_YUY2 (paintinfo * p, unsigned char *dest);
65 static void paint_setup_UYVY (paintinfo * p, unsigned char *dest);
66 static void paint_setup_YVYU (paintinfo * p, unsigned char *dest);
67 static void paint_setup_IYU2 (paintinfo * p, unsigned char *dest);
68 static void paint_setup_Y41B (paintinfo * p, unsigned char *dest);
69 static void paint_setup_Y42B (paintinfo * p, unsigned char *dest);
70 static void paint_setup_Y800 (paintinfo * p, unsigned char *dest);
71 static void paint_setup_AYUV (paintinfo * p, unsigned char *dest);
72
73 #if 0
74 static void paint_setup_IMC1 (paintinfo * p, unsigned char *dest);
75 static void paint_setup_IMC2 (paintinfo * p, unsigned char *dest);
76 static void paint_setup_IMC3 (paintinfo * p, unsigned char *dest);
77 static void paint_setup_IMC4 (paintinfo * p, unsigned char *dest);
78 #endif
79 static void paint_setup_YUV9 (paintinfo * p, unsigned char *dest);
80 static void paint_setup_YVU9 (paintinfo * p, unsigned char *dest);
81
82 int fourcc_get_size (struct fourcc_list_struct *fourcc, int w, int h);
83
84 struct fourcc_list_struct fourcc_list[] = {
85 /* packed */
86   {"YUY2", "YUY2", 16, paint_setup_YUY2},
87   {"UYVY", "UYVY", 16, paint_setup_UYVY},
88   {"Y422", "Y422", 16, paint_setup_UYVY},
89   {"UYNV", "UYNV", 16, paint_setup_UYVY},       /* FIXME: UYNV? */
90   {"YVYU", "YVYU", 16, paint_setup_YVYU},
91   {"AYUV", "AYUV", 32, paint_setup_AYUV},
92
93   /* interlaced */
94   /*{   "IUYV", "IUY2", 16, paint_setup_YVYU }, */
95
96   /* inverted */
97   /*{   "cyuv", "cyuv", 16, paint_setup_YVYU }, */
98
99   /*{   "Y41P", "Y41P", 12, paint_setup_YVYU }, */
100
101   /* interlaced */
102   /*{   "IY41", "IY41", 12, paint_setup_YVYU }, */
103
104   /*{   "Y211", "Y211", 8, paint_setup_YVYU }, */
105
106   /*{   "Y41T", "Y41T", 12, paint_setup_YVYU }, */
107   /*{   "Y42P", "Y42P", 16, paint_setup_YVYU }, */
108   /*{   "CLJR", "CLJR", 8, paint_setup_YVYU }, */
109   /*{   "IYU1", "IYU1", 12, paint_setup_YVYU }, */
110   {"IYU2", "IYU2", 24, paint_setup_IYU2},
111
112 /* planar */
113   /* YVU9 */
114   {"YVU9", "YVU9", 9, paint_setup_YVU9},
115   /* YUV9 */
116   {"YUV9", "YUV9", 9, paint_setup_YUV9},
117   /* IF09 */
118   /* YV12 */
119   {"YV12", "YV12", 12, paint_setup_YV12},
120   /* I420 */
121   {"I420", "I420", 12, paint_setup_I420},
122   /* NV12 */
123   /* NV21 */
124 #if 0
125   /* IMC1 */
126   {"IMC1", "IMC1", 16, paint_setup_IMC1},
127   /* IMC2 */
128   {"IMC2", "IMC2", 12, paint_setup_IMC2},
129   /* IMC3 */
130   {"IMC3", "IMC3", 16, paint_setup_IMC3},
131   /* IMC4 */
132   {"IMC4", "IMC4", 12, paint_setup_IMC4},
133 #endif
134   /* CLPL */
135   /* Y41B */
136   {"Y41B", "Y41B", 12, paint_setup_Y41B},
137   /* Y42B */
138   {"Y42B", "Y42B", 16, paint_setup_Y42B},
139   /* Y800 grayscale */
140   {"Y800", "Y800", 8, paint_setup_Y800}
141 };
142
143 /* returns the size in bytes for one video frame of the given dimensions
144  * given the fourcc */
145 int
146 fourcc_get_size (struct fourcc_list_struct *fourcc, int w, int h)
147 {
148   paintinfo pi = { NULL, };
149   paintinfo *p = &pi;
150
151   p->width = w;
152   p->height = h;
153
154   fourcc->paint_setup (p, NULL);
155
156   return (unsigned long) p->endptr;
157 }
158
159 static void
160 paint_setup_I420 (paintinfo * p, unsigned char *dest)
161 {
162   p->yp = dest;
163   p->ystride = GST_ROUND_UP_4 (p->width);
164   p->up = p->yp + p->ystride * GST_ROUND_UP_2 (p->height);
165   p->ustride = GST_ROUND_UP_8 (p->width) / 2;
166   p->vp = p->up + p->ustride * GST_ROUND_UP_2 (p->height) / 2;
167   p->vstride = GST_ROUND_UP_8 (p->ystride) / 2;
168   p->endptr = p->vp + p->vstride * GST_ROUND_UP_2 (p->height) / 2;
169 }
170
171 static void
172 paint_setup_YV12 (paintinfo * p, unsigned char *dest)
173 {
174   p->yp = dest;
175   p->ystride = GST_ROUND_UP_4 (p->width);
176   p->vp = p->yp + p->ystride * GST_ROUND_UP_2 (p->height);
177   p->vstride = GST_ROUND_UP_8 (p->ystride) / 2;
178   p->up = p->vp + p->vstride * GST_ROUND_UP_2 (p->height) / 2;
179   p->ustride = GST_ROUND_UP_8 (p->ystride) / 2;
180   p->endptr = p->up + p->ustride * GST_ROUND_UP_2 (p->height) / 2;
181 }
182
183 static void
184 paint_setup_AYUV (paintinfo * p, unsigned char *dest)
185 {
186   p->ap = dest;
187   p->yp = dest + 1;
188   p->up = dest + 2;
189   p->vp = dest + 3;
190   p->ystride = p->width * 4;
191   p->endptr = dest + p->ystride * p->height;
192 }
193
194 static void
195 paint_setup_YUY2 (paintinfo * p, unsigned char *dest)
196 {
197   p->yp = dest;
198   p->up = dest + 1;
199   p->vp = dest + 3;
200   p->ystride = GST_ROUND_UP_2 (p->width) * 2;
201   p->endptr = dest + p->ystride * p->height;
202 }
203
204 static void
205 paint_setup_UYVY (paintinfo * p, unsigned char *dest)
206 {
207   p->yp = dest + 1;
208   p->up = dest;
209   p->vp = dest + 2;
210   p->ystride = GST_ROUND_UP_2 (p->width) * 2;
211   p->endptr = dest + p->ystride * p->height;
212 }
213
214 static void
215 paint_setup_YVYU (paintinfo * p, unsigned char *dest)
216 {
217   p->yp = dest;
218   p->up = dest + 3;
219   p->vp = dest + 1;
220   p->ystride = GST_ROUND_UP_2 (p->width) * 2;
221   p->endptr = dest + p->ystride * p->height;
222 }
223
224 static void
225 paint_setup_IYU2 (paintinfo * p, unsigned char *dest)
226 {
227   /* untested */
228   p->yp = dest + 1;
229   p->up = dest + 0;
230   p->vp = dest + 2;
231   p->ystride = GST_ROUND_UP_4 (p->width * 3);
232   p->endptr = dest + p->ystride * p->height;
233 }
234
235 static void
236 paint_setup_Y41B (paintinfo * p, unsigned char *dest)
237 {
238   p->yp = dest;
239   p->ystride = GST_ROUND_UP_4 (p->width);
240   p->up = p->yp + p->ystride * p->height;
241   p->ustride = GST_ROUND_UP_16 (p->width) / 4;
242   p->vp = p->up + p->ustride * p->height;
243   p->vstride = GST_ROUND_UP_16 (p->width) / 4;
244   p->endptr = p->vp + p->vstride * p->height;
245 }
246
247 static void
248 paint_setup_Y42B (paintinfo * p, unsigned char *dest)
249 {
250   p->yp = dest;
251   p->ystride = GST_ROUND_UP_4 (p->width);
252   p->up = p->yp + p->ystride * p->height;
253   p->ustride = GST_ROUND_UP_8 (p->width) / 2;
254   p->vp = p->up + p->ustride * p->height;
255   p->vstride = GST_ROUND_UP_8 (p->width) / 2;
256   p->endptr = p->vp + p->vstride * p->height;
257 }
258
259 static void
260 paint_setup_Y800 (paintinfo * p, unsigned char *dest)
261 {
262   /* untested */
263   p->yp = dest;
264   p->ystride = GST_ROUND_UP_4 (p->width);
265   p->endptr = dest + p->ystride * p->height;
266 }
267
268 #if 0
269 static void
270 paint_setup_IMC1 (paintinfo * p, unsigned char *dest)
271 {
272   p->yp = dest;
273   p->up = dest + p->width * p->height;
274   p->vp = dest + p->width * p->height + p->width * p->height / 2;
275 }
276
277 static void
278 paint_setup_IMC2 (paintinfo * p, unsigned char *dest)
279 {
280   p->yp = dest;
281   p->vp = dest + p->width * p->height;
282   p->up = dest + p->width * p->height + p->width / 2;
283 }
284
285 static void
286 paint_setup_IMC3 (paintinfo * p, unsigned char *dest)
287 {
288   p->yp = dest;
289   p->up = dest + p->width * p->height + p->width * p->height / 2;
290   p->vp = dest + p->width * p->height;
291 }
292
293 static void
294 paint_setup_IMC4 (paintinfo * p, unsigned char *dest)
295 {
296   p->yp = dest;
297   p->vp = dest + p->width * p->height + p->width / 2;
298   p->up = dest + p->width * p->height;
299 }
300 #endif
301
302 static void
303 paint_setup_YVU9 (paintinfo * p, unsigned char *dest)
304 {
305   p->yp = dest;
306   p->ystride = GST_ROUND_UP_4 (p->width);
307   p->vp = p->yp + p->ystride * p->height;
308   p->vstride = GST_ROUND_UP_4 (p->ystride / 4);
309   p->up = p->vp + p->vstride * (GST_ROUND_UP_4 (p->height) / 4);
310   p->ustride = GST_ROUND_UP_4 (p->ystride / 4);
311   p->endptr = p->up + p->ustride * (GST_ROUND_UP_4 (p->height) / 4);
312 }
313
314 static void
315 paint_setup_YUV9 (paintinfo * p, unsigned char *dest)
316 {
317   p->yp = dest;
318   p->ystride = GST_ROUND_UP_4 (p->width);
319   p->up = p->yp + p->ystride * p->height;
320   p->ustride = GST_ROUND_UP_4 (p->ystride / 4);
321   p->vp = p->up + p->ustride * (GST_ROUND_UP_4 (p->height) / 4);
322   p->vstride = GST_ROUND_UP_4 (p->ystride / 4);
323   p->endptr = p->vp + p->vstride * (GST_ROUND_UP_4 (p->height) / 4);
324 }
325
326 #define gst_video_format_is_packed video_format_is_packed
327 static gboolean
328 video_format_is_packed (GstVideoFormat fmt)
329 {
330   switch (fmt) {
331     case GST_VIDEO_FORMAT_I420:
332     case GST_VIDEO_FORMAT_YV12:
333     case GST_VIDEO_FORMAT_Y41B:
334     case GST_VIDEO_FORMAT_Y42B:
335     case GST_VIDEO_FORMAT_Y800:
336     case GST_VIDEO_FORMAT_YUV9:
337     case GST_VIDEO_FORMAT_YVU9:
338       return FALSE;
339     case GST_VIDEO_FORMAT_IYU1:
340     case GST_VIDEO_FORMAT_YUY2:
341     case GST_VIDEO_FORMAT_YVYU:
342     case GST_VIDEO_FORMAT_UYVY:
343     case GST_VIDEO_FORMAT_AYUV:
344     case GST_VIDEO_FORMAT_RGBx:
345     case GST_VIDEO_FORMAT_BGRx:
346     case GST_VIDEO_FORMAT_xRGB:
347     case GST_VIDEO_FORMAT_xBGR:
348     case GST_VIDEO_FORMAT_RGBA:
349     case GST_VIDEO_FORMAT_BGRA:
350     case GST_VIDEO_FORMAT_ARGB:
351     case GST_VIDEO_FORMAT_ABGR:
352     case GST_VIDEO_FORMAT_RGB:
353     case GST_VIDEO_FORMAT_BGR:
354     case GST_VIDEO_FORMAT_RGB8_PALETTED:
355       return TRUE;
356     default:
357       g_return_val_if_reached (FALSE);
358   }
359   return FALSE;
360 }
361
362 GST_START_TEST (test_video_formats)
363 {
364   guint i;
365
366   for (i = 0; i < G_N_ELEMENTS (fourcc_list); ++i) {
367     GstVideoFormat fmt;
368     const gchar *s;
369     guint32 fourcc;
370     guint w, h;
371
372     s = fourcc_list[i].fourcc;
373     fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
374     fmt = gst_video_format_from_fourcc (fourcc);
375
376     if (fmt == GST_VIDEO_FORMAT_UNKNOWN)
377       continue;
378
379     GST_INFO ("Fourcc %s, packed=%d", fourcc_list[i].fourcc,
380         gst_video_format_is_packed (fmt));
381
382     fail_unless (gst_video_format_is_yuv (fmt));
383
384     /* use any non-NULL pointer so we can compare against NULL */
385     {
386       paintinfo paintinfo = { 0, };
387       fourcc_list[i].paint_setup (&paintinfo, (unsigned char *) s);
388       if (paintinfo.ap != NULL) {
389         fail_unless (gst_video_format_has_alpha (fmt));
390       } else {
391         fail_if (gst_video_format_has_alpha (fmt));
392       }
393     }
394
395     for (w = 1; w <= 65; ++w) {
396       for (h = 1; h <= 65; ++h) {
397         paintinfo paintinfo = { 0, };
398         guint off0, off1, off2, off3;
399         guint size;
400
401         GST_LOG ("%s, %dx%d", fourcc_list[i].fourcc, w, h);
402
403         paintinfo.width = w;
404         paintinfo.height = h;
405         fourcc_list[i].paint_setup (&paintinfo, NULL);
406         fail_unless_equals_int (gst_video_format_get_row_stride (fmt, 0, w),
407             paintinfo.ystride);
408         if (!gst_video_format_is_packed (fmt)
409             && !gst_video_format_is_gray (fmt)) {
410           /* planar */
411           fail_unless_equals_int (gst_video_format_get_row_stride (fmt, 1, w),
412               paintinfo.ustride);
413           fail_unless_equals_int (gst_video_format_get_row_stride (fmt, 2, w),
414               paintinfo.vstride);
415           /* check component_width * height against offsets/size somehow? */
416         }
417
418         size = gst_video_format_get_size (fmt, w, h);
419         off0 = gst_video_format_get_component_offset (fmt, 0, w, h);
420         off1 = gst_video_format_get_component_offset (fmt, 1, w, h);
421         off2 = gst_video_format_get_component_offset (fmt, 2, w, h);
422
423         fail_unless_equals_int (size, (unsigned long) paintinfo.endptr);
424         fail_unless_equals_int (off0, (unsigned long) paintinfo.yp);
425         fail_unless_equals_int (off1, (unsigned long) paintinfo.up);
426         fail_unless_equals_int (off2, (unsigned long) paintinfo.vp);
427
428         /* should be 0 if there's no alpha component */
429         off3 = gst_video_format_get_component_offset (fmt, 3, w, h);
430         fail_unless_equals_int (off3, (unsigned long) paintinfo.ap);
431
432         /* some gstvideo checks ... (FIXME: fails for Y41B and Y42B; not sure
433          * if the check or the _get_component_size implementation is wrong) */
434         if (fmt != GST_VIDEO_FORMAT_Y41B && fmt != GST_VIDEO_FORMAT_Y42B
435             && fmt != GST_VIDEO_FORMAT_Y800) {
436           guint cs0, cs1, cs2, cs3;
437
438           cs0 = gst_video_format_get_component_width (fmt, 0, w) *
439               gst_video_format_get_component_height (fmt, 0, h);
440           cs1 = gst_video_format_get_component_width (fmt, 1, w) *
441               gst_video_format_get_component_height (fmt, 1, h);
442           cs2 = gst_video_format_get_component_width (fmt, 2, w) *
443               gst_video_format_get_component_height (fmt, 2, h);
444
445           /* GST_LOG ("cs0=%d,cs1=%d,cs2=%d,off0=%d,off1=%d,off2=%d,size=%d",
446              cs0, cs1, cs2, off0, off1, off2, size); */
447
448           if (!gst_video_format_is_packed (fmt))
449             fail_unless (cs0 <= off1);
450
451           if (gst_video_format_has_alpha (fmt)) {
452             cs3 = gst_video_format_get_component_width (fmt, 3, w) *
453                 gst_video_format_get_component_height (fmt, 3, h);
454             fail_unless (cs3 < size);
455             /* U/V/alpha shouldn't take up more space than the Y component */
456             fail_if (cs1 > cs0, "cs1 (%d) should be <= cs0 (%d)", cs1, cs0);
457             fail_if (cs2 > cs0, "cs2 (%d) should be <= cs0 (%d)", cs2, cs0);
458             fail_if (cs3 > cs0, "cs3 (%d) should be <= cs0 (%d)", cs3, cs0);
459
460             /* all components together shouldn't take up more space than size */
461             fail_unless (cs0 + cs1 + cs2 + cs3 <= size);
462           } else {
463             /* U/V shouldn't take up more space than the Y component */
464             fail_if (cs1 > cs0, "cs1 (%d) should be <= cs0 (%d)", cs1, cs0);
465             fail_if (cs2 > cs0, "cs2 (%d) should be <= cs0 (%d)", cs2, cs0);
466
467             /* all components together shouldn't take up more space than size */
468             fail_unless (cs0 + cs1 + cs2 <= size,
469                 "cs0 (%d) + cs1 (%d) + cs2 (%d) should be <= size (%d)",
470                 cs0, cs1, cs2, size);
471           }
472         }
473       }
474     }
475   }
476 }
477
478 GST_END_TEST;
479
480 GST_START_TEST (test_video_formats_rgb)
481 {
482   gint width, height, framerate_n, framerate_d, par_n, par_d;
483   GstCaps *caps =
484       gst_video_format_new_caps (GST_VIDEO_FORMAT_RGB, 800, 600, 0, 1, 1, 1);
485   GstStructure *structure;
486
487   structure = gst_caps_get_structure (caps, 0);
488
489   fail_unless (gst_structure_get_int (structure, "width", &width));
490   fail_unless (gst_structure_get_int (structure, "height", &height));
491   fail_unless (gst_structure_get_fraction (structure, "framerate", &framerate_n,
492           &framerate_d));
493   fail_unless (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
494           &par_n, &par_d));
495
496   fail_unless (width == 800);
497   fail_unless (height == 600);
498   fail_unless (framerate_n == 0);
499   fail_unless (framerate_d == 1);
500   fail_unless (par_n == 1);
501   fail_unless (par_d == 1);
502
503   gst_caps_unref (caps);
504 }
505
506 GST_END_TEST;
507
508 GST_START_TEST (test_video_template_caps)
509 {
510   GstCaps *caps = gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGB);
511   gst_caps_unref (caps);
512 }
513
514 GST_END_TEST;
515
516
517 GST_START_TEST (test_dar_calc)
518 {
519   guint display_ratio_n, display_ratio_d;
520
521   /* Ensure that various Display Ratio calculations are correctly done */
522   /* video 768x576, par 16/15, display par 16/15 = 4/3 */
523   fail_unless (gst_video_calculate_display_ratio (&display_ratio_n,
524           &display_ratio_d, 768, 576, 16, 15, 16, 15));
525   fail_unless (display_ratio_n == 4 && display_ratio_d == 3);
526
527   /* video 720x480, par 32/27, display par 1/1 = 16/9 */
528   fail_unless (gst_video_calculate_display_ratio (&display_ratio_n,
529           &display_ratio_d, 720, 480, 32, 27, 1, 1));
530   fail_unless (display_ratio_n == 16 && display_ratio_d == 9);
531
532   /* video 360x288, par 533333/500000, display par 16/15 = 
533    * dar 1599999/1600000 */
534   fail_unless (gst_video_calculate_display_ratio (&display_ratio_n,
535           &display_ratio_d, 360, 288, 533333, 500000, 16, 15));
536   fail_unless (display_ratio_n == 1599999 && display_ratio_d == 1280000);
537 }
538
539 GST_END_TEST;
540
541 GST_START_TEST (test_parse_caps_rgb)
542 {
543   struct
544   {
545     const gchar *tmpl_caps_string;
546     GstVideoFormat fmt;
547   } formats[] = {
548     /* 24 bit */
549     {
550     GST_VIDEO_CAPS_RGB, GST_VIDEO_FORMAT_RGB}, {
551     GST_VIDEO_CAPS_BGR, GST_VIDEO_FORMAT_BGR},
552         /* 32 bit (no alpha) */
553     {
554     GST_VIDEO_CAPS_RGBx, GST_VIDEO_FORMAT_RGBx}, {
555     GST_VIDEO_CAPS_xRGB, GST_VIDEO_FORMAT_xRGB}, {
556     GST_VIDEO_CAPS_BGRx, GST_VIDEO_FORMAT_BGRx}, {
557     GST_VIDEO_CAPS_xBGR, GST_VIDEO_FORMAT_xBGR},
558         /* 32 bit (with alpha) */
559     {
560     GST_VIDEO_CAPS_RGBA, GST_VIDEO_FORMAT_RGBA}, {
561     GST_VIDEO_CAPS_ARGB, GST_VIDEO_FORMAT_ARGB}, {
562     GST_VIDEO_CAPS_BGRA, GST_VIDEO_FORMAT_BGRA}, {
563     GST_VIDEO_CAPS_ABGR, GST_VIDEO_FORMAT_ABGR}
564   };
565   gint i;
566
567   for (i = 0; i < G_N_ELEMENTS (formats); ++i) {
568     GstVideoFormat fmt = GST_VIDEO_FORMAT_UNKNOWN;
569     GstCaps *caps, *caps2;
570     int w = -1, h = -1;
571
572     caps = gst_caps_from_string (formats[i].tmpl_caps_string);
573     gst_caps_set_simple (caps, "width", G_TYPE_INT, 2 * (i + 1), "height",
574         G_TYPE_INT, i + 1, "framerate", GST_TYPE_FRACTION, 15, 1,
575         "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL);
576     g_assert (gst_caps_is_fixed (caps));
577
578     GST_DEBUG ("testing caps: %" GST_PTR_FORMAT, caps);
579
580     fail_unless (gst_video_format_parse_caps (caps, &fmt, &w, &h));
581     fail_unless_equals_int (fmt, formats[i].fmt);
582     fail_unless_equals_int (w, 2 * (i + 1));
583     fail_unless_equals_int (h, i + 1);
584
585     /* make sure they're serialised back correctly */
586     caps2 = gst_video_format_new_caps (fmt, w, h, 15, 1, 1, 1);
587     fail_unless (caps != NULL);
588     fail_unless (gst_caps_is_equal (caps, caps2));
589
590     gst_caps_unref (caps);
591     gst_caps_unref (caps2);
592   }
593 }
594
595 GST_END_TEST;
596
597 GST_START_TEST (test_events)
598 {
599   GstEvent *e;
600   gboolean in_still;
601
602   e = gst_video_event_new_still_frame (TRUE);
603   fail_if (e == NULL, "Failed to create still frame event");
604   fail_unless (gst_video_event_parse_still_frame (e, &in_still),
605       "Failed to parse still frame event");
606   fail_unless (gst_video_event_parse_still_frame (e, NULL),
607       "Failed to parse still frame event w/ in_still == NULL");
608   fail_unless (in_still == TRUE);
609   gst_event_unref (e);
610
611   e = gst_video_event_new_still_frame (FALSE);
612   fail_if (e == NULL, "Failed to create still frame event");
613   fail_unless (gst_video_event_parse_still_frame (e, &in_still),
614       "Failed to parse still frame event");
615   fail_unless (gst_video_event_parse_still_frame (e, NULL),
616       "Failed to parse still frame event w/ in_still == NULL");
617   fail_unless (in_still == FALSE);
618   gst_event_unref (e);
619 }
620
621 GST_END_TEST;
622
623 GST_START_TEST (test_convert_frame)
624 {
625   GstCaps *from_caps, *to_caps;
626   GstBuffer *from_buffer, *to_buffer;
627   GError *error = NULL;
628   gint i;
629   guint8 *data;
630
631   gst_debug_set_threshold_for_name ("default", GST_LEVEL_NONE);
632
633   from_buffer = gst_buffer_new_and_alloc (640 * 480 * 4);
634   data = GST_BUFFER_DATA (from_buffer);
635
636   for (i = 0; i < 640 * 480; i++) {
637     data[4 * i + 0] = 0;        /* x */
638     data[4 * i + 1] = 255;      /* R */
639     data[4 * i + 2] = 0;        /* G */
640     data[4 * i + 3] = 0;        /* B */
641   }
642   from_caps = gst_video_format_new_caps (GST_VIDEO_FORMAT_xRGB,
643       640, 480, 25, 1, 1, 1);
644   gst_buffer_set_caps (from_buffer, from_caps);
645
646   to_caps =
647       gst_caps_from_string
648       ("something/that, does=(string)not, exist=(boolean)FALSE");
649
650   to_buffer =
651       gst_video_convert_frame (from_buffer, to_caps, GST_CLOCK_TIME_NONE,
652       &error);
653   fail_if (to_buffer != NULL);
654   fail_unless (error != NULL);
655   g_error_free (error);
656   error = NULL;
657
658   gst_caps_unref (to_caps);
659   to_caps =
660       gst_video_format_new_caps (GST_VIDEO_FORMAT_I420, 240, 320, 25, 1, 1, 2);
661   to_buffer =
662       gst_video_convert_frame (from_buffer, to_caps, GST_CLOCK_TIME_NONE,
663       &error);
664   fail_unless (to_buffer != NULL);
665   fail_unless (gst_caps_can_intersect (to_caps, GST_BUFFER_CAPS (to_buffer)));
666   fail_unless (error == NULL);
667
668   gst_buffer_unref (from_buffer);
669   gst_caps_unref (from_caps);
670   gst_buffer_unref (to_buffer);
671   gst_caps_unref (to_caps);
672 }
673
674 GST_END_TEST;
675
676 typedef struct
677 {
678   GMainLoop *loop;
679   GstBuffer *buffer;
680   GError *error;
681 } ConvertFrameContext;
682
683 static void
684 convert_frame_async_callback (GstBuffer * buf, GError * err,
685     ConvertFrameContext * cf_data)
686 {
687   cf_data->buffer = buf;
688   cf_data->error = err;
689
690   g_main_loop_quit (cf_data->loop);
691 }
692
693 GST_START_TEST (test_convert_frame_async)
694 {
695   GstCaps *from_caps, *to_caps;
696   GstBuffer *from_buffer;
697   gint i;
698   guint8 *data;
699   GMainLoop *loop;
700   ConvertFrameContext cf_data = { NULL, NULL, NULL };
701
702   gst_debug_set_threshold_for_name ("default", GST_LEVEL_NONE);
703
704   from_buffer = gst_buffer_new_and_alloc (640 * 480 * 4);
705   data = GST_BUFFER_DATA (from_buffer);
706
707   for (i = 0; i < 640 * 480; i++) {
708     data[4 * i + 0] = 0;        /* x */
709     data[4 * i + 1] = 255;      /* R */
710     data[4 * i + 2] = 0;        /* G */
711     data[4 * i + 3] = 0;        /* B */
712   }
713   from_caps = gst_video_format_new_caps (GST_VIDEO_FORMAT_xRGB,
714       640, 480, 25, 1, 1, 1);
715   gst_buffer_set_caps (from_buffer, from_caps);
716
717   to_caps =
718       gst_caps_from_string
719       ("something/that, does=(string)not, exist=(boolean)FALSE");
720
721   loop = cf_data.loop = g_main_loop_new (NULL, FALSE);
722
723   gst_video_convert_frame_async (from_buffer, to_caps, GST_CLOCK_TIME_NONE,
724       (GstVideoConvertFrameCallback) convert_frame_async_callback, &cf_data,
725       NULL);
726
727   g_main_loop_run (loop);
728
729   fail_if (cf_data.buffer != NULL);
730   fail_unless (cf_data.error != NULL);
731   g_error_free (cf_data.error);
732   cf_data.error = NULL;
733
734   gst_caps_unref (to_caps);
735   to_caps =
736       gst_video_format_new_caps (GST_VIDEO_FORMAT_I420, 240, 320, 25, 1, 1, 2);
737   gst_video_convert_frame_async (from_buffer, to_caps, GST_CLOCK_TIME_NONE,
738       (GstVideoConvertFrameCallback) convert_frame_async_callback, &cf_data,
739       NULL);
740   g_main_loop_run (loop);
741   fail_unless (cf_data.buffer != NULL);
742   fail_unless (gst_caps_can_intersect (to_caps,
743           GST_BUFFER_CAPS (cf_data.buffer)));
744   fail_unless (cf_data.error == NULL);
745
746   gst_buffer_unref (from_buffer);
747   gst_caps_unref (from_caps);
748   gst_buffer_unref (cf_data.buffer);
749   gst_caps_unref (to_caps);
750
751   g_main_loop_unref (loop);
752 }
753
754 GST_END_TEST;
755
756 GST_START_TEST (test_video_size_from_caps)
757 {
758   gint size;
759   guint32 fourcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
760   GstCaps *caps = gst_caps_new_simple ("video/x-raw-yuv",
761       "format", GST_TYPE_FOURCC, fourcc,
762       "width", G_TYPE_INT, 640,
763       "height", G_TYPE_INT, 480,
764       "framerate", GST_TYPE_FRACTION, 25, 1,
765       NULL);
766
767   fail_unless (gst_video_get_size_from_caps (caps, &size));
768   fail_unless (size ==
769       gst_video_format_get_size (gst_video_format_from_fourcc (fourcc), 640,
770           480));
771   fail_unless (size == (640 * 480 * 12 / 8));
772
773   gst_caps_unref (caps);
774 }
775
776 GST_END_TEST;
777
778 #undef ASSERT_CRITICAL
779 #define ASSERT_CRITICAL(code) while(0){}        /* nothing */
780
781 GST_START_TEST (test_overlay_composition)
782 {
783   GstVideoOverlayComposition *comp1, *comp2;
784   GstVideoOverlayRectangle *rect1, *rect2;
785   GstBuffer *pix1, *pix2, *buf;
786   guint seq1, seq2;
787   guint w, h, stride;
788   gint x, y;
789
790   pix1 = gst_buffer_new_and_alloc (200 * sizeof (guint32) * 50);
791   memset (GST_BUFFER_DATA (pix1), 0, GST_BUFFER_SIZE (pix1));
792
793   rect1 = gst_video_overlay_rectangle_new_argb (pix1, 200, 50, 200 * 4,
794       600, 50, 300, 50, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
795
796   gst_buffer_unref (pix1);
797   pix1 = NULL;
798
799   comp1 = gst_video_overlay_composition_new (rect1);
800   fail_unless (gst_video_overlay_composition_n_rectangles (comp1) == 1);
801   fail_unless (gst_video_overlay_composition_get_rectangle (comp1, 0) == rect1);
802   fail_unless (gst_video_overlay_composition_get_rectangle (comp1, 1) == NULL);
803
804   /* rectangle was created first, sequence number should be smaller */
805   seq1 = gst_video_overlay_rectangle_get_seqnum (rect1);
806   seq2 = gst_video_overlay_composition_get_seqnum (comp1);
807   fail_unless (seq1 < seq2);
808
809   /* composition took own ref, so refcount is 2 now, so this should fail */
810   ASSERT_CRITICAL (gst_video_overlay_rectangle_set_render_rectangle (rect1, 50,
811           600, 300, 50));
812
813   /* drop our ref, so refcount is 1 (we know it will continue to be valid) */
814   gst_video_overlay_rectangle_unref (rect1);
815   gst_video_overlay_rectangle_set_render_rectangle (rect1, 50, 600, 300, 50);
816
817   comp2 = gst_video_overlay_composition_new (rect1);
818   fail_unless (gst_video_overlay_composition_n_rectangles (comp2) == 1);
819   fail_unless (gst_video_overlay_composition_get_rectangle (comp2, 0) == rect1);
820   fail_unless (gst_video_overlay_composition_get_rectangle (comp2, 1) == NULL);
821
822   fail_unless (seq1 < gst_video_overlay_composition_get_seqnum (comp2));
823   fail_unless (seq2 < gst_video_overlay_composition_get_seqnum (comp2));
824
825   /* now refcount is 2 again because comp2 has also taken a ref, so must fail */
826   ASSERT_CRITICAL (gst_video_overlay_rectangle_set_render_rectangle (rect1, 0,
827           0, 1, 1));
828
829   /* this should make a copy of the rectangles so drop the original
830    * second ref on rect1 */
831   comp2 = gst_video_overlay_composition_make_writable (comp2);
832   gst_video_overlay_rectangle_set_render_rectangle (rect1, 51, 601, 301, 51);
833
834   rect2 = gst_video_overlay_composition_get_rectangle (comp2, 0);
835   fail_unless (gst_video_overlay_composition_n_rectangles (comp2) == 1);
836   fail_unless (gst_video_overlay_composition_get_rectangle (comp2, 0) == rect2);
837   fail_unless (gst_video_overlay_composition_get_rectangle (comp2, 1) == NULL);
838   fail_unless (rect1 != rect2);
839
840   gst_video_overlay_composition_add_rectangle (comp1, rect2);
841   gst_video_overlay_composition_ref (comp1);
842   ASSERT_CRITICAL (gst_video_overlay_composition_add_rectangle (comp1, rect2));
843   gst_video_overlay_composition_unref (comp1);
844
845   /* make sure the copy really worked */
846   gst_video_overlay_rectangle_get_render_rectangle (rect1, &x, &y, &w, &h);
847   fail_unless_equals_int (x, 51);
848   fail_unless_equals_int (y, 601);
849   fail_unless_equals_int (w, 301);
850   fail_unless_equals_int (h, 51);
851
852   /* get scaled pixbuf and touch last byte */
853   pix1 = gst_video_overlay_rectangle_get_pixels_argb (rect1, &stride,
854       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
855   fail_unless (GST_BUFFER_SIZE (pix1) > ((h - 1) * stride + (w * 4) - 1),
856       "size %u vs. last pixel offset %u", GST_BUFFER_SIZE (pix1),
857       ((h - 1) * stride + (w * 4) - 1));
858   fail_unless_equals_int (*(GST_BUFFER_DATA (pix1) + ((h - 1) * stride +
859               (w * 4) - 1)), 0);
860
861   gst_video_overlay_rectangle_get_render_rectangle (rect2, &x, &y, &w, &h);
862   fail_unless_equals_int (x, 50);
863   fail_unless_equals_int (y, 600);
864   fail_unless_equals_int (w, 300);
865   fail_unless_equals_int (h, 50);
866
867   /* get scaled pixbuf and touch last byte */
868   pix2 = gst_video_overlay_rectangle_get_pixels_argb (rect2, &stride,
869       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
870   fail_unless (GST_BUFFER_SIZE (pix2) > ((h - 1) * stride + (w * 4) - 1),
871       "size %u vs. last pixel offset %u", GST_BUFFER_SIZE (pix1),
872       ((h - 1) * stride + (w * 4) - 1));
873   fail_unless_equals_int (*(GST_BUFFER_DATA (pix2) + ((h - 1) * stride +
874               (w * 4) - 1)), 0);
875
876   /* get scaled pixbuf again, should be the same buffer as before (caching) */
877   pix1 = gst_video_overlay_rectangle_get_pixels_argb (rect2, &stride,
878       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
879   fail_unless (pix1 == pix2);
880
881   /* now compare the original unscaled ones */
882   pix1 = gst_video_overlay_rectangle_get_pixels_unscaled_argb (rect1, &w, &h,
883       &stride, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
884   pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_argb (rect2, &w, &h,
885       &stride, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
886
887   /* the original pixel buffers should be identical */
888   fail_unless (pix1 == pix2);
889   fail_unless_equals_int (w, 200);
890   fail_unless_equals_int (h, 50);
891
892   /* touch last byte */
893   fail_unless (GST_BUFFER_SIZE (pix1) > ((h - 1) * stride + (w * 4) - 1),
894       "size %u vs. last pixel offset %u", GST_BUFFER_SIZE (pix1),
895       ((h - 1) * stride + (w * 4) - 1));
896   fail_unless_equals_int (*(GST_BUFFER_DATA (pix1) + ((h - 1) * stride +
897               (w * 4) - 1)), 0);
898
899   /* test attaching and retrieving of compositions to/from buffers */
900   buf = gst_buffer_new ();
901   fail_unless (gst_video_buffer_get_overlay_composition (buf) == NULL);
902
903   gst_buffer_ref (buf);
904   ASSERT_CRITICAL (gst_video_buffer_set_overlay_composition (buf, comp1));
905   gst_buffer_unref (buf);
906   gst_video_buffer_set_overlay_composition (buf, comp1);
907   fail_unless (gst_video_buffer_get_overlay_composition (buf) == comp1);
908   gst_video_buffer_set_overlay_composition (buf, comp2);
909   fail_unless (gst_video_buffer_get_overlay_composition (buf) == comp2);
910   gst_video_buffer_set_overlay_composition (buf, NULL);
911   fail_unless (gst_video_buffer_get_overlay_composition (buf) == NULL);
912
913   /* make sure the buffer cleans up its composition ref when unreffed */
914   gst_video_buffer_set_overlay_composition (buf, comp2);
915   gst_buffer_unref (buf);
916
917   gst_video_overlay_composition_unref (comp2);
918   gst_video_overlay_composition_unref (comp1);
919 }
920
921 GST_END_TEST;
922
923 static Suite *
924 video_suite (void)
925 {
926   Suite *s = suite_create ("video support library");
927   TCase *tc_chain = tcase_create ("general");
928
929   suite_add_tcase (s, tc_chain);
930   tcase_add_test (tc_chain, test_video_formats);
931   tcase_add_test (tc_chain, test_video_formats_rgb);
932   tcase_add_test (tc_chain, test_video_template_caps);
933   tcase_add_test (tc_chain, test_dar_calc);
934   tcase_add_test (tc_chain, test_parse_caps_rgb);
935   tcase_add_test (tc_chain, test_events);
936   tcase_add_test (tc_chain, test_convert_frame);
937   tcase_add_test (tc_chain, test_convert_frame_async);
938   tcase_add_test (tc_chain, test_video_size_from_caps);
939   tcase_add_test (tc_chain, test_overlay_composition);
940
941   return s;
942 }
943
944 GST_CHECK_MAIN (video);