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