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