winks: sort devices that look like cameras first
[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 typedef struct _KsVideoDeviceEntry KsVideoDeviceEntry;
41
42 struct _KsVideoDeviceEntry
43 {
44   KsDeviceEntry *device;
45   gint priority;
46 };
47
48 static void
49 ks_video_device_entry_decide_priority (KsVideoDeviceEntry * videodevice)
50 {
51   HANDLE filter_handle;
52
53   videodevice->priority = 0;
54
55   filter_handle = CreateFile (videodevice->device->path,
56       GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
57       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
58   if (ks_is_valid_handle (filter_handle)) {
59     GUID *propsets = NULL;
60     gulong propsets_len;
61
62     if (ks_object_get_supported_property_sets (filter_handle, &propsets,
63             &propsets_len)) {
64       gulong i;
65
66       for (i = 0; i < propsets_len; i++) {
67         if (memcmp (&propsets[i], &PROPSETID_VIDCAP_CAMERACONTROL,
68                 sizeof (GUID)) == 0) {
69           videodevice->priority++;
70           break;
71         }
72       }
73
74       g_free (propsets);
75     }
76   }
77
78   CloseHandle (filter_handle);
79 }
80
81 static gint
82 ks_video_device_entry_compare (gconstpointer a, gconstpointer b)
83 {
84   const KsVideoDeviceEntry *videodevice_a = a;
85   const KsVideoDeviceEntry *videodevice_b = b;
86
87   if (videodevice_a->priority > videodevice_b->priority)
88     return -1;
89   else if (videodevice_a->priority == videodevice_b->priority)
90     return 0;
91   else
92     return 1;
93 }
94
95 GList *
96 ks_video_device_list_sort_cameras_first (GList * devices)
97 {
98   GList *videodevices = NULL, *walk;
99   guint i;
100
101   for (walk = devices; walk != NULL; walk = walk->next) {
102     KsDeviceEntry *device = walk->data;
103     KsVideoDeviceEntry *videodevice;
104
105     videodevice = g_new (KsVideoDeviceEntry, 1);
106     videodevice->device = device;
107     ks_video_device_entry_decide_priority (videodevice);
108
109     videodevices = g_list_append (videodevices, videodevice);
110   }
111
112   videodevices = g_list_sort (videodevices, ks_video_device_entry_compare);
113
114   g_list_free (devices);
115   devices = NULL;
116
117   for (walk = videodevices, i = 0; walk != NULL; walk = walk->next, i++) {
118     KsVideoDeviceEntry *videodevice = walk->data;
119
120     videodevice->device->index = i;
121     devices = g_list_append (devices, videodevice->device);
122
123     g_free (videodevice);
124   }
125
126   g_list_free (videodevices);
127
128   return devices;
129 }
130
131 static GstStructure *
132 ks_video_format_to_structure (GUID subtype_guid, GUID format_guid)
133 {
134   GstStructure *structure = NULL;
135
136   if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_MJPG) || IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_TVMJ) ||     /* FIXME: NOT tested */
137       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_WAKE) ||        /* FIXME: NOT tested */
138       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_CFCC) ||        /* FIXME: NOT tested */
139       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_IJPG)) {        /* FIXME: NOT tested */
140     structure = gst_structure_new ("image/jpeg", NULL);
141   } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB555) ||       /* FIXME: NOT tested */
142       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB565) ||      /* FIXME: NOT tested */
143       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB24) || IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB32) ||   /* FIXME: NOT tested */
144       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB1555) ||    /* FIXME: NOT tested */
145       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB32) ||      /* FIXME: NOT tested */
146       IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB4444)) {    /* FIXME: NOT tested */
147     guint depth = 0, bpp = 0;
148     gint endianness = 0;
149     guint32 r_mask = 0, b_mask = 0, g_mask = 0;
150
151     if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB555)) {
152       bpp = 16;
153       depth = 15;
154       endianness = G_BIG_ENDIAN;
155       r_mask = 0x7c00;
156       g_mask = 0x03e0;
157       b_mask = 0x001f;
158     } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB565)) {
159       bpp = depth = 16;
160       endianness = G_BIG_ENDIAN;
161       r_mask = 0xf800;
162       g_mask = 0x07e0;
163       b_mask = 0x001f;
164     } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB24)) {
165       bpp = depth = 24;
166       endianness = G_BIG_ENDIAN;
167       r_mask = 0x0000ff;
168       g_mask = 0x00ff00;
169       b_mask = 0xff0000;
170     } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB32)) {
171       bpp = 32;
172       depth = 24;
173       endianness = G_BIG_ENDIAN;
174       r_mask = 0x000000ff;
175       g_mask = 0x0000ff00;
176       b_mask = 0x00ff0000;
177       /* FIXME: check
178        *r_mask = 0xff000000;
179        *g_mask = 0x00ff0000;
180        *b_mask = 0x0000ff00;
181        */
182     } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB1555)) {
183       bpp = 16;
184       depth = 15;
185       endianness = G_BIG_ENDIAN;
186       r_mask = 0x7c00;
187       g_mask = 0x03e0;
188       b_mask = 0x001f;
189     } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB32)) {
190       bpp = depth = 32;
191       endianness = G_BIG_ENDIAN;
192       r_mask = 0x000000ff;
193       g_mask = 0x0000ff00;
194       b_mask = 0x00ff0000;
195       /* FIXME: check
196        *r_mask = 0xff000000;
197        *g_mask = 0x00ff0000;
198        *b_mask = 0x0000ff00;
199        */
200     } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB4444)) {
201       bpp = 16;
202       depth = 12;
203       endianness = G_BIG_ENDIAN;
204       r_mask = 0x0f00;
205       g_mask = 0x00f0;
206       b_mask = 0x000f;
207       //r_mask = 0x000f;
208       //g_mask = 0x00f0;
209       //b_mask = 0x0f00;
210     } else {
211       g_assert_not_reached ();
212     }
213
214     structure = gst_structure_new ("video/x-raw-rgb",
215         "bpp", G_TYPE_INT, bpp,
216         "depth", G_TYPE_INT, depth,
217         "red_mask", G_TYPE_INT, r_mask,
218         "green_mask", G_TYPE_INT, g_mask,
219         "blue_mask", G_TYPE_INT, b_mask,
220         "endianness", G_TYPE_INT, endianness, NULL);
221   } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_dvsd)) {
222     if (IsEqualGUID (&format_guid, &FORMAT_DvInfo)) {
223       structure = gst_structure_new ("video/x-dv",
224           "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
225     } else if (IsEqualGUID (&format_guid, &FORMAT_VideoInfo)) {
226       structure = gst_structure_new ("video/x-dv",
227           "systemstream", G_TYPE_BOOLEAN, FALSE,
228           "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('d', 'v', 's', 'd'),
229           NULL);
230     }
231   } else if (memcmp (&subtype_guid.Data2, &MEDIASUBTYPE_FOURCC.Data2,
232           sizeof (subtype_guid) - sizeof (subtype_guid.Data1)) == 0) {
233     guint8 *p = (guint8 *) & subtype_guid.Data1;
234
235     structure = gst_structure_new ("video/x-raw-yuv",
236         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC (p[0], p[1], p[2], p[3]),
237         NULL);
238   }
239
240   if (!structure) {
241     GST_DEBUG ("Unknown DirectShow Video GUID %08x-%04x-%04x-%04x-%08x%04x",
242         subtype_guid.Data1, subtype_guid.Data2, subtype_guid.Data3,
243         *(WORD *) subtype_guid.Data4, *(DWORD *) & subtype_guid.Data4[2],
244         *(WORD *) & subtype_guid.Data4[6]);
245   }
246
247   return structure;
248 }
249
250 static void
251 guess_aspect (gint width, gint height, gint * par_width, gint * par_height)
252 {
253   /*
254    * As we dont have access to the actual pixel aspect, we will try to do a
255    * best-effort guess. The guess is based on most sensors being either 4/3
256    * or 16/9, and most pixel aspects being close to 1/1.
257    */
258   if ((width == 768) && (height == 448)) {      /* special case for w448p */
259     *par_width = 28;
260     *par_height = 27;
261   } else {
262     if (((float) width / (float) height) < 1.2778) {
263       *par_width = 12;
264       *par_height = 11;
265     } else {
266       *par_width = 1;
267       *par_height = 1;
268     }
269   }
270 }
271
272 static gboolean
273 ks_video_append_video_stream_cfg_fields (GstStructure * structure,
274     const KS_VIDEO_STREAM_CONFIG_CAPS * vscc)
275 {
276   g_return_val_if_fail (structure, FALSE);
277   g_return_val_if_fail (vscc, FALSE);
278
279   /* width */
280   if (vscc->MinOutputSize.cx == vscc->MaxOutputSize.cx) {
281     gst_structure_set (structure,
282         "width", G_TYPE_INT, vscc->MaxOutputSize.cx, NULL);
283   } else {
284     gst_structure_set (structure,
285         "width", GST_TYPE_INT_RANGE,
286         vscc->MinOutputSize.cx, vscc->MaxOutputSize.cx, NULL);
287   }
288
289   /* height */
290   if (vscc->MinOutputSize.cy == vscc->MaxOutputSize.cy) {
291     gst_structure_set (structure,
292         "height", G_TYPE_INT, vscc->MaxOutputSize.cy, NULL);
293   } else {
294     gst_structure_set (structure,
295         "height", GST_TYPE_INT_RANGE,
296         vscc->MinOutputSize.cy, vscc->MaxOutputSize.cy, NULL);
297   }
298
299   /* framerate */
300   if (vscc->MinFrameInterval == vscc->MaxFrameInterval) {
301     gst_structure_set (structure,
302         "framerate", GST_TYPE_FRACTION,
303         (gint) (10000000 / vscc->MaxFrameInterval), 1, NULL);
304   } else {
305     gst_structure_set (structure,
306         "framerate", GST_TYPE_FRACTION_RANGE,
307         (gint) (10000000 / vscc->MaxFrameInterval), 1,
308         (gint) (10000000 / vscc->MinFrameInterval), 1, NULL);
309   }
310
311   {
312     gint par_width, par_height;
313
314     guess_aspect (vscc->MaxOutputSize.cx, vscc->MaxOutputSize.cy,
315         &par_width, &par_height);
316
317     gst_structure_set (structure,
318         "pixel-aspect-ratio", GST_TYPE_FRACTION, par_width, par_height, NULL);
319   }
320
321   return TRUE;
322 }
323
324 KsVideoMediaType *
325 ks_video_media_type_dup (KsVideoMediaType * media_type)
326 {
327   KsVideoMediaType *result = g_new (KsVideoMediaType, 1);
328
329   memcpy (result, media_type, sizeof (KsVideoMediaType));
330
331   result->range = g_malloc (media_type->range->FormatSize);
332   memcpy ((gpointer) result->range, media_type->range,
333       media_type->range->FormatSize);
334
335   result->format = g_malloc (media_type->format_size);
336   memcpy (result->format, media_type->format, media_type->format_size);
337
338   result->translated_caps = gst_caps_ref (media_type->translated_caps);
339
340   return result;
341 }
342
343 void
344 ks_video_media_type_free (KsVideoMediaType * media_type)
345 {
346   if (media_type == NULL)
347     return;
348
349   g_free ((gpointer) media_type->range);
350
351   g_free (media_type->format);
352
353   if (media_type->translated_caps != NULL)
354     gst_caps_unref (media_type->translated_caps);
355
356   g_free (media_type);
357 }
358
359 static GList *
360 ks_video_media_type_list_remove_duplicates (GList * media_types)
361 {
362   GList *master, *duplicates;
363
364   do {
365     GList *entry;
366
367     master = duplicates = NULL;
368
369     /* Find the first set of duplicates and their master */
370     for (entry = media_types; entry != NULL && duplicates == NULL;
371         entry = entry->next) {
372       KsVideoMediaType *mt = entry->data;
373       GList *other_entry;
374
375       for (other_entry = media_types; other_entry != NULL;
376           other_entry = other_entry->next) {
377         KsVideoMediaType *other_mt = other_entry->data;
378
379         if (other_mt == mt)
380           continue;
381
382         if (gst_caps_is_equal (mt->translated_caps, other_mt->translated_caps))
383           duplicates = g_list_prepend (duplicates, other_mt);
384       }
385
386       if (duplicates != NULL)
387         master = entry;
388     }
389
390     if (duplicates != NULL) {
391       KsVideoMediaType *selected_mt = master->data;
392
393       /*
394        * Pick a FORMAT_VideoInfo2 if present, if not we just stay with the
395        * first entry
396        */
397       for (entry = duplicates; entry != NULL; entry = entry->next) {
398         KsVideoMediaType *mt = entry->data;
399
400         if (IsEqualGUID (&mt->range->Specifier, &FORMAT_VideoInfo2)) {
401           ks_video_media_type_free (selected_mt);
402           selected_mt = mt;
403         } else {
404           ks_video_media_type_free (mt);
405         }
406
407         /* Remove the dupe from the main list */
408         media_types = g_list_remove (media_types, mt);
409       }
410
411       /* Update master node with the selected MediaType */
412       master->data = selected_mt;
413
414       g_list_free (duplicates);
415     }
416   }
417   while (master != NULL);
418
419   return media_types;
420 }
421
422 GList *
423 ks_video_probe_filter_for_caps (HANDLE filter_handle)
424 {
425   GList *ret = NULL;
426   gulong pin_count;
427   guint pin_id;
428
429   if (!ks_filter_get_pin_property (filter_handle, 0, KSPROPSETID_Pin,
430           KSPROPERTY_PIN_CTYPES, &pin_count, sizeof (pin_count)))
431     goto beach;
432
433   GST_DEBUG ("pin_count = %d", pin_count);
434
435   for (pin_id = 0; pin_id < pin_count; pin_id++) {
436     KSPIN_COMMUNICATION pin_comm;
437     KSPIN_DATAFLOW pin_flow;
438     GUID pin_cat;
439
440     if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
441             KSPROPERTY_PIN_COMMUNICATION, &pin_comm, sizeof (pin_comm)))
442       continue;
443
444     if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
445             KSPROPERTY_PIN_DATAFLOW, &pin_flow, sizeof (pin_flow)))
446       continue;
447
448     if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
449             KSPROPERTY_PIN_CATEGORY, &pin_cat, sizeof (pin_cat)))
450       continue;
451
452     GST_DEBUG ("pin[%u]: pin_comm=%d, pin_flow=%d", pin_id, pin_comm, pin_flow);
453
454     if (pin_flow == KSPIN_DATAFLOW_OUT &&
455         memcmp (&pin_cat, &PINNAME_CAPTURE, sizeof (GUID)) == 0) {
456       KSMULTIPLE_ITEM *items;
457
458       if (ks_filter_get_pin_property_multi (filter_handle, pin_id,
459               KSPROPSETID_Pin, KSPROPERTY_PIN_DATARANGES, &items)) {
460         KSDATARANGE *range = (KSDATARANGE *) (items + 1);
461         guint i;
462
463         for (i = 0; i < items->Count; i++) {
464           if (IsEqualGUID (&range->MajorFormat, &KSDATAFORMAT_TYPE_VIDEO)) {
465             KsVideoMediaType *entry;
466             gpointer src_vscc, src_format;
467             GstStructure *media_structure;
468
469             entry = g_new0 (KsVideoMediaType, 1);
470             entry->pin_id = pin_id;
471
472             entry->range = g_malloc (range->FormatSize);
473             memcpy ((gpointer) entry->range, range, range->FormatSize);
474
475             if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo)) {
476               KS_DATARANGE_VIDEO *vr = (KS_DATARANGE_VIDEO *) entry->range;
477
478               src_vscc = &vr->ConfigCaps;
479               src_format = &vr->VideoInfoHeader;
480
481               entry->format_size = sizeof (vr->VideoInfoHeader);
482               entry->sample_size = vr->VideoInfoHeader.bmiHeader.biSizeImage;
483             } else if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo2)) {
484               KS_DATARANGE_VIDEO2 *vr = (KS_DATARANGE_VIDEO2 *) entry->range;
485
486               src_vscc = &vr->ConfigCaps;
487               src_format = &vr->VideoInfoHeader;
488
489               entry->format_size = sizeof (vr->VideoInfoHeader);
490               entry->sample_size = vr->VideoInfoHeader.bmiHeader.biSizeImage;
491             } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEGVideo)) {
492               /* Untested and probably wrong... */
493               KS_DATARANGE_MPEG1_VIDEO *vr =
494                   (KS_DATARANGE_MPEG1_VIDEO *) entry->range;
495
496               src_vscc = &vr->ConfigCaps;
497               src_format = &vr->VideoInfoHeader;
498
499               entry->format_size = sizeof (vr->VideoInfoHeader);
500               entry->sample_size =
501                   vr->VideoInfoHeader.hdr.bmiHeader.biSizeImage;
502             } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEG2Video)) {
503               /* Untested and probably wrong... */
504               KS_DATARANGE_MPEG2_VIDEO *vr =
505                   (KS_DATARANGE_MPEG2_VIDEO *) entry->range;
506
507               src_vscc = &vr->ConfigCaps;
508               src_format = &vr->VideoInfoHeader;
509
510               entry->format_size = sizeof (vr->VideoInfoHeader);
511               entry->sample_size =
512                   vr->VideoInfoHeader.hdr.bmiHeader.biSizeImage;
513             } else {
514               gchar *guid_str;
515
516               guid_str = ks_guid_to_string (&range->Specifier);
517               GST_DEBUG ("pin[%u]: ignoring unknown specifier GUID %s",
518                   pin_id, guid_str);
519               g_free (guid_str);
520
521               ks_video_media_type_free (entry);
522               entry = NULL;
523             }
524
525             if (entry != NULL) {
526               g_assert (entry->sample_size != 0);
527
528               memcpy ((gpointer) & entry->vscc, src_vscc, sizeof (entry->vscc));
529
530               entry->format = g_malloc (entry->format_size);
531               memcpy (entry->format, src_format, entry->format_size);
532
533               media_structure =
534                   ks_video_format_to_structure (range->SubFormat,
535                   range->MajorFormat);
536
537               if (media_structure == NULL) {
538                 g_warning ("ks_video_format_to_structure returned NULL");
539                 ks_video_media_type_free (entry);
540                 entry = NULL;
541               } else if (ks_video_append_video_stream_cfg_fields
542                   (media_structure, &entry->vscc)) {
543                 entry->translated_caps = gst_caps_new_empty ();
544                 gst_caps_append_structure (entry->translated_caps,
545                     media_structure);
546               } else {
547                 gst_structure_free (media_structure);
548                 ks_video_media_type_free (entry);
549                 entry = NULL;
550               }
551
552               if (entry != NULL)
553                 ret = g_list_prepend (ret, entry);
554             }
555           }
556
557           /* REVISIT: Each KSDATARANGE should start on a 64-bit boundary */
558           range = (KSDATARANGE *) (((guchar *) range) + range->FormatSize);
559         }
560
561         g_free (items);
562       }
563     }
564   }
565
566   if (ret != NULL) {
567     ret = g_list_reverse (ret);
568     ret = ks_video_media_type_list_remove_duplicates (ret);
569   }
570
571 beach:
572   return ret;
573 }
574
575 KSPIN_CONNECT *
576 ks_video_create_pin_conn_from_media_type (KsVideoMediaType * media_type)
577 {
578   KSPIN_CONNECT *conn = NULL;
579   KSDATAFORMAT *format = NULL;
580   guint8 *vih;
581
582   conn = g_malloc0 (sizeof (KSPIN_CONNECT) + sizeof (KSDATAFORMAT) +
583       media_type->format_size);
584
585   conn->Interface.Set = KSINTERFACESETID_Standard;
586   conn->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
587   conn->Interface.Flags = 0;
588
589   conn->Medium.Set = KSMEDIUMSETID_Standard;
590   conn->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
591   conn->Medium.Flags = 0;
592
593   conn->PinId = media_type->pin_id;
594   conn->PinToHandle = NULL;
595   conn->Priority.PriorityClass = KSPRIORITY_NORMAL;
596   conn->Priority.PrioritySubClass = 1;
597
598   format = (KSDATAFORMAT *) (conn + 1);
599   memcpy (format, media_type->range, sizeof (KSDATAFORMAT));
600   format->FormatSize = sizeof (KSDATAFORMAT) + media_type->format_size;
601
602   vih = (guint8 *) (format + 1);
603   memcpy (vih, media_type->format, media_type->format_size);
604
605   return conn;
606 }
607
608 gboolean
609 ks_video_fixate_media_type (const KSDATARANGE * range,
610     guint8 * format, gint width, gint height, gint fps_n, gint fps_d)
611 {
612   DWORD dwRate = (width * height * fps_n) / fps_d;
613
614   g_return_val_if_fail (format != NULL, FALSE);
615
616   if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo)) {
617     KS_VIDEOINFOHEADER *vih = (KS_VIDEOINFOHEADER *) format;
618
619     /* FIXME: Need to figure out how to properly handle ranges */
620     if (vih->bmiHeader.biWidth != width || vih->bmiHeader.biHeight != height)
621       return FALSE;
622
623     vih->AvgTimePerFrame = gst_util_uint64_scale_int (10000000, fps_d, fps_n);
624     vih->dwBitRate = dwRate * vih->bmiHeader.biBitCount;
625   } else if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo2)) {
626     KS_VIDEOINFOHEADER2 *vih = (KS_VIDEOINFOHEADER2 *) format;
627
628     /* FIXME: see above */
629     if (vih->bmiHeader.biWidth != width || vih->bmiHeader.biHeight != height)
630       return FALSE;
631
632     vih->AvgTimePerFrame = gst_util_uint64_scale_int (10000000, fps_d, fps_n);
633     vih->dwBitRate = dwRate * vih->bmiHeader.biBitCount;
634   } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEGVideo)) {
635     KS_MPEG1VIDEOINFO *vih = (KS_MPEG1VIDEOINFO *) format;
636
637     /* FIXME: see above */
638     if (vih->hdr.bmiHeader.biWidth != width ||
639         vih->hdr.bmiHeader.biHeight != height)
640     {
641       return FALSE;
642     }
643
644     vih->hdr.AvgTimePerFrame =
645         gst_util_uint64_scale_int (10000000, fps_d, fps_n);
646     vih->hdr.dwBitRate = dwRate * vih->hdr.bmiHeader.biBitCount;
647   } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEG2Video)) {
648     KS_MPEGVIDEOINFO2 *vih = (KS_MPEGVIDEOINFO2 *) format;
649
650     /* FIXME: see above */
651     if (vih->hdr.bmiHeader.biWidth != width ||
652         vih->hdr.bmiHeader.biHeight != height)
653     {
654       return FALSE;
655     }
656
657     vih->hdr.AvgTimePerFrame =
658         gst_util_uint64_scale_int (10000000, fps_d, fps_n);
659     vih->hdr.dwBitRate = dwRate * vih->hdr.bmiHeader.biBitCount;
660   } else {
661     return FALSE;
662   }
663
664   return TRUE;
665 }
666
667 static GstStructure *
668 ks_video_append_var_video_fields (GstStructure * structure)
669 {
670   if (structure) {
671     gst_structure_set (structure,
672         "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
673         "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
674         "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
675   }
676
677   return structure;
678 }
679
680 GstCaps *
681 ks_video_get_all_caps (void)
682 {
683   static GstCaps *caps = NULL;
684
685   if (caps == NULL) {
686     GstStructure *structure;
687     caps = gst_caps_new_empty ();
688
689     /* from Windows SDK 6.0 uuids.h */
690     /* RGB formats */
691     structure =
692         ks_video_append_var_video_fields (ks_video_format_to_structure
693         (MEDIASUBTYPE_RGB555, FORMAT_VideoInfo));
694     gst_caps_append_structure (caps, structure);
695
696     structure =
697         ks_video_append_var_video_fields (ks_video_format_to_structure
698         (MEDIASUBTYPE_RGB565, FORMAT_VideoInfo));
699     gst_caps_append_structure (caps, structure);
700
701     structure =
702         ks_video_append_var_video_fields (ks_video_format_to_structure
703         (MEDIASUBTYPE_RGB24, FORMAT_VideoInfo));
704     gst_caps_append_structure (caps, structure);
705
706     structure =
707         ks_video_append_var_video_fields (ks_video_format_to_structure
708         (MEDIASUBTYPE_RGB32, FORMAT_VideoInfo));
709     gst_caps_append_structure (caps, structure);
710
711     /* YUV formats */
712     structure =
713         ks_video_append_var_video_fields (gst_structure_new ("video/x-raw-yuv",
714             NULL));
715     gst_caps_append_structure (caps, structure);
716
717     /* Other formats */
718     structure =
719         ks_video_append_var_video_fields (ks_video_format_to_structure
720         (MEDIASUBTYPE_MJPG, FORMAT_VideoInfo));
721     gst_caps_append_structure (caps, structure);
722
723     structure =
724         ks_video_append_var_video_fields (ks_video_format_to_structure
725         (MEDIASUBTYPE_dvsd, FORMAT_VideoInfo));
726     gst_caps_append_structure (caps, structure);
727
728     structure =                 /* no variable video fields (width, height, framerate) */
729         ks_video_format_to_structure (MEDIASUBTYPE_dvsd, FORMAT_DvInfo);
730     gst_caps_append_structure (caps, structure);
731   }
732
733   return caps;
734 }