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