winks: provide guessed pixel-aspect-ratio in caps
[platform/upstream/gstreamer.git] / sys / winks / ksvideohelpers.c
1 /*
2  * Copyright (C) 2007 Haakon Sporsheim <hakon.sporsheim@tandberg.com>
3  *               2008 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
4  *               2009 Knut Inge Hvidsten <knut.inge.hvidsten@tandberg.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "ksvideohelpers.h"
23
24 #include <uuids.h>
25 #include "kshelpers.h"
26
27 GST_DEBUG_CATEGORY_EXTERN (gst_ks_debug);
28 #define GST_CAT_DEFAULT gst_ks_debug
29
30 static const GUID MEDIASUBTYPE_FOURCC =
31     { 0x0 /* FourCC here */ , 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xAA, 0x00,
32     0x38, 0x9B, 0x71}
33 };
34
35 extern const GUID MEDIASUBTYPE_I420 =
36     { 0x30323449, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B,
37     0x71}
38 };
39
40 static GstStructure *
41 ks_video_format_to_structure (GUID subtype_guid, GUID format_guid)
42 {
43   GstStructure *structure = NULL;
44
45   if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_MJPG) || IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_TVMJ) ||     /* FIXME: NOT tested */
46       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_WAKE) ||        /* FIXME: NOT tested */
47       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_CFCC) ||        /* FIXME: NOT tested */
48       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_IJPG)) {        /* FIXME: NOT tested */
49     structure = gst_structure_new ("image/jpeg", NULL);
50   } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB555) ||       /* FIXME: NOT tested */
51       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB565) ||      /* FIXME: NOT tested */
52       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB24) || IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB32) ||   /* FIXME: NOT tested */
53       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB1555) ||    /* FIXME: NOT tested */
54       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB32) ||      /* FIXME: NOT tested */
55       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB4444)) {    /* FIXME: NOT tested */
56     guint depth = 0, bpp = 0;
57     gint endianness = 0;
58     guint32 r_mask = 0, b_mask = 0, g_mask = 0;
59
60     if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB555)) {
61       bpp = 16;
62       depth = 15;
63       endianness = G_BIG_ENDIAN;
64       r_mask = 0x7c00;
65       g_mask = 0x03e0;
66       b_mask = 0x001f;
67     } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB565)) {
68       bpp = depth = 16;
69       endianness = G_BIG_ENDIAN;
70       r_mask = 0xf800;
71       g_mask = 0x07e0;
72       b_mask = 0x001f;
73     } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB24)) {
74       bpp = depth = 24;
75       endianness = G_BIG_ENDIAN;
76       r_mask = 0x0000ff;
77       g_mask = 0x00ff00;
78       b_mask = 0xff0000;
79     } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB32)) {
80       bpp = 32;
81       depth = 24;
82       endianness = G_BIG_ENDIAN;
83       r_mask = 0x000000ff;
84       g_mask = 0x0000ff00;
85       b_mask = 0x00ff0000;
86       /* FIXME: check
87        *r_mask = 0xff000000;
88        *g_mask = 0x00ff0000;
89        *b_mask = 0x0000ff00;
90        */
91     } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB1555)) {
92       bpp = 16;
93       depth = 15;
94       endianness = G_BIG_ENDIAN;
95       r_mask = 0x7c00;
96       g_mask = 0x03e0;
97       b_mask = 0x001f;
98     } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB32)) {
99       bpp = depth = 32;
100       endianness = G_BIG_ENDIAN;
101       r_mask = 0x000000ff;
102       g_mask = 0x0000ff00;
103       b_mask = 0x00ff0000;
104       /* FIXME: check
105        *r_mask = 0xff000000;
106        *g_mask = 0x00ff0000;
107        *b_mask = 0x0000ff00;
108        */
109     } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB4444)) {
110       bpp = 16;
111       depth = 12;
112       endianness = G_BIG_ENDIAN;
113       r_mask = 0x0f00;
114       g_mask = 0x00f0;
115       b_mask = 0x000f;
116       //r_mask = 0x000f;
117       //g_mask = 0x00f0;
118       //b_mask = 0x0f00;
119     } else {
120       g_assert_not_reached ();
121     }
122
123     structure = gst_structure_new ("video/x-raw-rgb",
124         "bpp", G_TYPE_INT, bpp,
125         "depth", G_TYPE_INT, depth,
126         "red_mask", G_TYPE_INT, r_mask,
127         "green_mask", G_TYPE_INT, g_mask,
128         "blue_mask", G_TYPE_INT, b_mask,
129         "endianness", G_TYPE_INT, endianness, NULL);
130   } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_dvsd)) {
131     if (IsEqualGUID (&format_guid, &FORMAT_DvInfo)) {
132       structure = gst_structure_new ("video/x-dv",
133           "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
134     } else if (IsEqualGUID (&format_guid, &FORMAT_VideoInfo)) {
135       structure = gst_structure_new ("video/x-dv",
136           "systemstream", G_TYPE_BOOLEAN, FALSE,
137           "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('d', 'v', 's', 'd'),
138           NULL);
139     }
140   } else if (memcmp (&subtype_guid.Data2, &MEDIASUBTYPE_FOURCC.Data2,
141           sizeof (subtype_guid) - sizeof (subtype_guid.Data1)) == 0) {
142     guint8 *p = (guint8 *) & subtype_guid.Data1;
143
144     structure = gst_structure_new ("video/x-raw-yuv",
145         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC (p[0], p[1], p[2], p[3]),
146         NULL);
147   }
148
149   if (!structure) {
150     GST_DEBUG ("Unknown DirectShow Video GUID %08x-%04x-%04x-%04x-%08x%04x",
151         subtype_guid.Data1, subtype_guid.Data2, subtype_guid.Data3,
152         *(WORD *) subtype_guid.Data4, *(DWORD *) & subtype_guid.Data4[2],
153         *(WORD *) & subtype_guid.Data4[6]);
154   }
155
156   return structure;
157 }
158
159 static void
160 guess_aspect (gint width, gint height, gint * par_width, gint * par_height)
161 {
162   /*
163    * As we dont have access to the actual pixel aspect, we will try to do a
164    * best-effort guess. The guess is based on most sensors being either 4/3
165    * or 16/9, and most pixel aspects being close to 1/1.
166    */
167   if ((width == 768) && (height == 448)) {      /* special case for w448p */
168     *par_width = 28;
169     *par_height = 27;
170   } else {
171     if (((float) width / (float) height) < 1.2778) {
172       *par_width = 12;
173       *par_height = 11;
174     } else {
175       *par_width = 1;
176       *par_height = 1;
177     }
178   }
179 }
180
181 static gboolean
182 ks_video_append_video_stream_cfg_fields (GstStructure * structure,
183     const KS_VIDEO_STREAM_CONFIG_CAPS * vscc)
184 {
185   g_return_val_if_fail (structure, FALSE);
186   g_return_val_if_fail (vscc, FALSE);
187
188   /* width */
189   if (vscc->MinOutputSize.cx == vscc->MaxOutputSize.cx) {
190     gst_structure_set (structure,
191         "width", G_TYPE_INT, vscc->MaxOutputSize.cx, NULL);
192   } else {
193     gst_structure_set (structure,
194         "width", GST_TYPE_INT_RANGE,
195         vscc->MinOutputSize.cx, vscc->MaxOutputSize.cx, NULL);
196   }
197
198   /* height */
199   if (vscc->MinOutputSize.cy == vscc->MaxOutputSize.cy) {
200     gst_structure_set (structure,
201         "height", G_TYPE_INT, vscc->MaxOutputSize.cy, NULL);
202   } else {
203     gst_structure_set (structure,
204         "height", GST_TYPE_INT_RANGE,
205         vscc->MinOutputSize.cy, vscc->MaxOutputSize.cy, NULL);
206   }
207
208   /* framerate */
209   if (vscc->MinFrameInterval == vscc->MaxFrameInterval) {
210     gst_structure_set (structure,
211         "framerate", GST_TYPE_FRACTION,
212         (gint) (10000000 / vscc->MaxFrameInterval), 1, NULL);
213   } else {
214     gst_structure_set (structure,
215         "framerate", GST_TYPE_FRACTION_RANGE,
216         (gint) (10000000 / vscc->MaxFrameInterval), 1,
217         (gint) (10000000 / vscc->MinFrameInterval), 1, NULL);
218   }
219
220   {
221     gint par_width, par_height;
222
223     guess_aspect (vscc->MaxOutputSize.cx, vscc->MaxOutputSize.cy,
224         &par_width, &par_height);
225
226     gst_structure_set (structure,
227         "pixel-aspect-ratio", GST_TYPE_FRACTION, par_width, par_height, NULL);
228   }
229
230   return TRUE;
231 }
232
233 KsVideoMediaType *
234 ks_video_media_type_dup (KsVideoMediaType * media_type)
235 {
236   KsVideoMediaType *result = g_new (KsVideoMediaType, 1);
237
238   memcpy (result, media_type, sizeof (KsVideoMediaType));
239
240   result->range = g_malloc (media_type->range->FormatSize);
241   memcpy ((gpointer) result->range, media_type->range,
242       media_type->range->FormatSize);
243
244   result->format = g_malloc (media_type->format_size);
245   memcpy (result->format, media_type->format, media_type->format_size);
246
247   result->translated_caps = gst_caps_ref (media_type->translated_caps);
248
249   return result;
250 }
251
252 void
253 ks_video_media_type_free (KsVideoMediaType * media_type)
254 {
255   if (media_type == NULL)
256     return;
257
258   g_free ((gpointer) media_type->range);
259
260   g_free (media_type->format);
261
262   if (media_type->translated_caps != NULL)
263     gst_caps_unref (media_type->translated_caps);
264
265   g_free (media_type);
266 }
267
268 static GList *
269 ks_video_media_type_list_remove_duplicates (GList * media_types)
270 {
271   GList *master, *duplicates;
272
273   do {
274     GList *entry;
275
276     master = duplicates = NULL;
277
278     /* Find the first set of duplicates and their master */
279     for (entry = media_types; entry != NULL && duplicates == NULL;
280         entry = entry->next) {
281       KsVideoMediaType *mt = entry->data;
282       GList *other_entry;
283
284       for (other_entry = media_types; other_entry != NULL;
285           other_entry = other_entry->next) {
286         KsVideoMediaType *other_mt = other_entry->data;
287
288         if (other_mt == mt)
289           continue;
290
291         if (gst_caps_is_equal (mt->translated_caps, other_mt->translated_caps))
292           duplicates = g_list_prepend (duplicates, other_mt);
293       }
294
295       if (duplicates != NULL)
296         master = entry;
297     }
298
299     if (duplicates != NULL) {
300       KsVideoMediaType *selected_mt = master->data;
301
302       /*
303        * Pick a FORMAT_VideoInfo2 if present, if not we just stay with the
304        * first entry
305        */
306       for (entry = duplicates; entry != NULL; entry = entry->next) {
307         KsVideoMediaType *mt = entry->data;
308
309         if (IsEqualGUID (&mt->range->Specifier, &FORMAT_VideoInfo2)) {
310           ks_video_media_type_free (selected_mt);
311           selected_mt = mt;
312         } else {
313           ks_video_media_type_free (mt);
314         }
315
316         /* Remove the dupe from the main list */
317         media_types = g_list_remove (media_types, mt);
318       }
319
320       /* Update master node with the selected MediaType */
321       master->data = selected_mt;
322
323       g_list_free (duplicates);
324     }
325   }
326   while (master != NULL);
327
328   return media_types;
329 }
330
331 GList *
332 ks_video_probe_filter_for_caps (HANDLE filter_handle)
333 {
334   GList *ret = NULL;
335   gulong pin_count;
336   guint pin_id;
337
338   if (!ks_filter_get_pin_property (filter_handle, 0, KSPROPSETID_Pin,
339           KSPROPERTY_PIN_CTYPES, &pin_count, sizeof (pin_count)))
340     goto beach;
341
342   GST_DEBUG ("pin_count = %d", pin_count);
343
344   for (pin_id = 0; pin_id < pin_count; pin_id++) {
345     KSPIN_COMMUNICATION pin_comm;
346     KSPIN_DATAFLOW pin_flow;
347     GUID pin_cat;
348
349     if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
350             KSPROPERTY_PIN_COMMUNICATION, &pin_comm, sizeof (pin_comm)))
351       continue;
352
353     if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
354             KSPROPERTY_PIN_DATAFLOW, &pin_flow, sizeof (pin_flow)))
355       continue;
356
357     if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
358             KSPROPERTY_PIN_CATEGORY, &pin_cat, sizeof (pin_cat)))
359       continue;
360
361     GST_DEBUG ("pin[%u]: pin_comm=%d, pin_flow=%d", pin_id, pin_comm, pin_flow);
362
363     if (pin_flow == KSPIN_DATAFLOW_OUT &&
364         memcmp (&pin_cat, &PINNAME_CAPTURE, sizeof (GUID)) == 0) {
365       KSMULTIPLE_ITEM *items;
366
367       if (ks_filter_get_pin_property_multi (filter_handle, pin_id,
368               KSPROPSETID_Pin, KSPROPERTY_PIN_DATARANGES, &items)) {
369         KSDATARANGE *range = (KSDATARANGE *) (items + 1);
370         guint i;
371
372         for (i = 0; i < items->Count; i++) {
373           if (IsEqualGUID (&range->MajorFormat, &KSDATAFORMAT_TYPE_VIDEO)) {
374             KsVideoMediaType *entry;
375             gpointer src_vscc, src_format;
376             GstStructure *media_structure;
377
378             entry = g_new0 (KsVideoMediaType, 1);
379             entry->pin_id = pin_id;
380
381             entry->range = g_malloc (range->FormatSize);
382             memcpy ((gpointer) entry->range, range, range->FormatSize);
383
384             if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo)) {
385               KS_DATARANGE_VIDEO *vr = (KS_DATARANGE_VIDEO *) entry->range;
386
387               src_vscc = &vr->ConfigCaps;
388               src_format = &vr->VideoInfoHeader;
389
390               entry->format_size = sizeof (vr->VideoInfoHeader);
391               entry->sample_size = vr->VideoInfoHeader.bmiHeader.biSizeImage;
392             } else if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo2)) {
393               KS_DATARANGE_VIDEO2 *vr = (KS_DATARANGE_VIDEO2 *) entry->range;
394
395               src_vscc = &vr->ConfigCaps;
396               src_format = &vr->VideoInfoHeader;
397
398               entry->format_size = sizeof (vr->VideoInfoHeader);
399               entry->sample_size = vr->VideoInfoHeader.bmiHeader.biSizeImage;
400             } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEGVideo)) {
401               /* Untested and probably wrong... */
402               KS_DATARANGE_MPEG1_VIDEO *vr =
403                   (KS_DATARANGE_MPEG1_VIDEO *) entry->range;
404
405               src_vscc = &vr->ConfigCaps;
406               src_format = &vr->VideoInfoHeader;
407
408               entry->format_size = sizeof (vr->VideoInfoHeader);
409               entry->sample_size =
410                   vr->VideoInfoHeader.hdr.bmiHeader.biSizeImage;
411             } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEG2Video)) {
412               /* Untested and probably wrong... */
413               KS_DATARANGE_MPEG2_VIDEO *vr =
414                   (KS_DATARANGE_MPEG2_VIDEO *) entry->range;
415
416               src_vscc = &vr->ConfigCaps;
417               src_format = &vr->VideoInfoHeader;
418
419               entry->format_size = sizeof (vr->VideoInfoHeader);
420               entry->sample_size =
421                   vr->VideoInfoHeader.hdr.bmiHeader.biSizeImage;
422             } else {
423               gchar *guid_str;
424
425               guid_str = ks_guid_to_string (&range->Specifier);
426               GST_DEBUG ("pin[%u]: ignoring unknown specifier GUID %s",
427                   pin_id, guid_str);
428               g_free (guid_str);
429
430               ks_video_media_type_free (entry);
431               entry = NULL;
432             }
433
434             if (entry != NULL) {
435               g_assert (entry->sample_size != 0);
436
437               memcpy ((gpointer) & entry->vscc, src_vscc, sizeof (entry->vscc));
438
439               entry->format = g_malloc (entry->format_size);
440               memcpy (entry->format, src_format, entry->format_size);
441
442               media_structure =
443                   ks_video_format_to_structure (range->SubFormat,
444                   range->MajorFormat);
445
446               if (media_structure == NULL) {
447                 g_warning ("ks_video_format_to_structure returned NULL");
448                 ks_video_media_type_free (entry);
449                 entry = NULL;
450               } else if (ks_video_append_video_stream_cfg_fields
451                   (media_structure, &entry->vscc)) {
452                 entry->translated_caps = gst_caps_new_empty ();
453                 gst_caps_append_structure (entry->translated_caps,
454                     media_structure);
455               } else {
456                 gst_structure_free (media_structure);
457                 ks_video_media_type_free (entry);
458                 entry = NULL;
459               }
460
461               if (entry != NULL)
462                 ret = g_list_prepend (ret, entry);
463             }
464           }
465
466           /* REVISIT: Each KSDATARANGE should start on a 64-bit boundary */
467           range = (KSDATARANGE *) (((guchar *) range) + range->FormatSize);
468         }
469
470         g_free (items);
471       }
472     }
473   }
474
475   if (ret != NULL) {
476     ret = g_list_reverse (ret);
477     ret = ks_video_media_type_list_remove_duplicates (ret);
478   }
479
480 beach:
481   return ret;
482 }
483
484 KSPIN_CONNECT *
485 ks_video_create_pin_conn_from_media_type (KsVideoMediaType * media_type)
486 {
487   KSPIN_CONNECT *conn = NULL;
488   KSDATAFORMAT *format = NULL;
489   guint8 *vih;
490
491   conn = g_malloc0 (sizeof (KSPIN_CONNECT) + sizeof (KSDATAFORMAT) +
492       media_type->format_size);
493
494   conn->Interface.Set = KSINTERFACESETID_Standard;
495   conn->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
496   conn->Interface.Flags = 0;
497
498   conn->Medium.Set = KSMEDIUMSETID_Standard;
499   conn->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
500   conn->Medium.Flags = 0;
501
502   conn->PinId = media_type->pin_id;
503   conn->PinToHandle = NULL;
504   conn->Priority.PriorityClass = KSPRIORITY_NORMAL;
505   conn->Priority.PrioritySubClass = 1;
506
507   format = (KSDATAFORMAT *) (conn + 1);
508   memcpy (format, media_type->range, sizeof (KSDATAFORMAT));
509   format->FormatSize = sizeof (KSDATAFORMAT) + media_type->format_size;
510
511   vih = (guint8 *) (format + 1);
512   memcpy (vih, media_type->format, media_type->format_size);
513
514   return conn;
515 }
516
517 gboolean
518 ks_video_fixate_media_type (const KSDATARANGE * range,
519     guint8 * format, gint width, gint height, gint fps_n, gint fps_d)
520 {
521   DWORD dwRate = (width * height * fps_n) / fps_d;
522
523   g_return_val_if_fail (format != NULL, FALSE);
524
525   if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo)) {
526     KS_VIDEOINFOHEADER *vih = (KS_VIDEOINFOHEADER *) format;
527
528     /* FIXME: Need to figure out how to properly handle ranges */
529     if (vih->bmiHeader.biWidth != width || vih->bmiHeader.biHeight != height)
530       return FALSE;
531
532     vih->AvgTimePerFrame = gst_util_uint64_scale_int (10000000, fps_d, fps_n);
533     vih->dwBitRate = dwRate * vih->bmiHeader.biBitCount;
534   } else if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo2)) {
535     KS_VIDEOINFOHEADER2 *vih = (KS_VIDEOINFOHEADER2 *) format;
536
537     /* FIXME: see above */
538     if (vih->bmiHeader.biWidth != width || vih->bmiHeader.biHeight != height)
539       return FALSE;
540
541     vih->AvgTimePerFrame = gst_util_uint64_scale_int (10000000, fps_d, fps_n);
542     vih->dwBitRate = dwRate * vih->bmiHeader.biBitCount;
543   } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEGVideo)) {
544     KS_MPEG1VIDEOINFO *vih = (KS_MPEG1VIDEOINFO *) format;
545
546     /* FIXME: see above */
547     if (vih->hdr.bmiHeader.biWidth != width ||
548         vih->hdr.bmiHeader.biHeight != height)
549     {
550       return FALSE;
551     }
552
553     vih->hdr.AvgTimePerFrame =
554         gst_util_uint64_scale_int (10000000, fps_d, fps_n);
555     vih->hdr.dwBitRate = dwRate * vih->hdr.bmiHeader.biBitCount;
556   } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEG2Video)) {
557     KS_MPEGVIDEOINFO2 *vih = (KS_MPEGVIDEOINFO2 *) format;
558
559     /* FIXME: see above */
560     if (vih->hdr.bmiHeader.biWidth != width ||
561         vih->hdr.bmiHeader.biHeight != height)
562     {
563       return FALSE;
564     }
565
566     vih->hdr.AvgTimePerFrame =
567         gst_util_uint64_scale_int (10000000, fps_d, fps_n);
568     vih->hdr.dwBitRate = dwRate * vih->hdr.bmiHeader.biBitCount;
569   } else {
570     return FALSE;
571   }
572
573   return TRUE;
574 }
575
576 static GstStructure *
577 ks_video_append_var_video_fields (GstStructure * structure)
578 {
579   if (structure) {
580     gst_structure_set (structure,
581         "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
582         "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
583         "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
584   }
585
586   return structure;
587 }
588
589 GstCaps *
590 ks_video_get_all_caps (void)
591 {
592   static GstCaps *caps = NULL;
593
594   if (caps == NULL) {
595     GstStructure *structure;
596     caps = gst_caps_new_empty ();
597
598     /* from Windows SDK 6.0 uuids.h */
599     /* RGB formats */
600     structure =
601         ks_video_append_var_video_fields (ks_video_format_to_structure
602         (MEDIASUBTYPE_RGB555, FORMAT_VideoInfo));
603     gst_caps_append_structure (caps, structure);
604
605     structure =
606         ks_video_append_var_video_fields (ks_video_format_to_structure
607         (MEDIASUBTYPE_RGB565, FORMAT_VideoInfo));
608     gst_caps_append_structure (caps, structure);
609
610     structure =
611         ks_video_append_var_video_fields (ks_video_format_to_structure
612         (MEDIASUBTYPE_RGB24, FORMAT_VideoInfo));
613     gst_caps_append_structure (caps, structure);
614
615     structure =
616         ks_video_append_var_video_fields (ks_video_format_to_structure
617         (MEDIASUBTYPE_RGB32, FORMAT_VideoInfo));
618     gst_caps_append_structure (caps, structure);
619
620     /* YUV formats */
621     structure =
622         ks_video_append_var_video_fields (gst_structure_new ("video/x-raw-yuv",
623             NULL));
624     gst_caps_append_structure (caps, structure);
625
626     /* Other formats */
627     structure =
628         ks_video_append_var_video_fields (ks_video_format_to_structure
629         (MEDIASUBTYPE_MJPG, FORMAT_VideoInfo));
630     gst_caps_append_structure (caps, structure);
631
632     structure =
633         ks_video_append_var_video_fields (ks_video_format_to_structure
634         (MEDIASUBTYPE_dvsd, FORMAT_VideoInfo));
635     gst_caps_append_structure (caps, structure);
636
637     structure =                 /* no variable video fields (width, height, framerate) */
638         ks_video_format_to_structure (MEDIASUBTYPE_dvsd, FORMAT_DvInfo);
639     gst_caps_append_structure (caps, structure);
640   }
641
642   return caps;
643 }