sys/winks/ksvideohelpers.c (ks_video_media_type_free): Avoid leaking the KSDATARANGE...
[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[%d]: 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               g_assert_not_reached ();
391
392             g_assert (entry->sample_size != 0);
393
394             memcpy ((gpointer) & entry->vscc, src_vscc, sizeof (entry->vscc));
395
396             entry->format = g_malloc (entry->format_size);
397             memcpy (entry->format, src_format, entry->format_size);
398
399             media_structure =
400                 ks_video_format_to_structure (range->SubFormat,
401                 range->MajorFormat);
402
403             if (media_structure == NULL) {
404               g_warning ("ks_video_format_to_structure returned NULL");
405               ks_video_media_type_free (entry);
406               entry = NULL;
407             } else if (ks_video_append_video_stream_cfg_fields (media_structure,
408                     &entry->vscc)) {
409               entry->translated_caps = gst_caps_new_empty ();
410               gst_caps_append_structure (entry->translated_caps,
411                   media_structure);
412             } else {
413               gst_structure_free (media_structure);
414               ks_video_media_type_free (entry);
415               entry = NULL;
416             }
417
418             if (entry != NULL)
419               ret = g_list_prepend (ret, entry);
420           }
421
422           /* REVISIT: Each KSDATARANGE should start on a 64-bit boundary */
423           range = (KSDATARANGE *) (((guchar *) range) + range->FormatSize);
424         }
425       }
426     }
427   }
428
429   if (ret != NULL) {
430     ret = g_list_reverse (ret);
431     ret = ks_video_media_type_list_remove_duplicates (ret);
432   }
433
434 beach:
435   return ret;
436 }
437
438 KSPIN_CONNECT *
439 ks_video_create_pin_conn_from_media_type (KsVideoMediaType * media_type)
440 {
441   KSPIN_CONNECT *conn = NULL;
442   KSDATAFORMAT *format = NULL;
443   guint8 *vih;
444
445   conn = g_malloc0 (sizeof (KSPIN_CONNECT) + sizeof (KSDATAFORMAT) +
446       media_type->format_size);
447
448   conn->Interface.Set = KSINTERFACESETID_Standard;
449   conn->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
450   conn->Interface.Flags = 0;
451
452   conn->Medium.Set = KSMEDIUMSETID_Standard;
453   conn->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
454   conn->Medium.Flags = 0;
455
456   conn->PinId = media_type->pin_id;
457   conn->PinToHandle = NULL;
458   conn->Priority.PriorityClass = KSPRIORITY_NORMAL;
459   conn->Priority.PrioritySubClass = 1;
460
461   format = (KSDATAFORMAT *) (conn + 1);
462   memcpy (format, media_type->range, sizeof (KSDATAFORMAT));
463   format->FormatSize = sizeof (KSDATAFORMAT) + media_type->format_size;
464
465   vih = (guint8 *) (format + 1);
466   memcpy (vih, media_type->format, media_type->format_size);
467
468   return conn;
469 }
470
471 gboolean
472 ks_video_fixate_media_type (const KSDATARANGE * range,
473     guint8 * format, gint width, gint height, gint fps_n, gint fps_d)
474 {
475   DWORD dwRate = (width * height * fps_n) / fps_d;
476
477   g_return_val_if_fail (format != NULL, FALSE);
478
479   if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo)) {
480     KS_VIDEOINFOHEADER *vih = (KS_VIDEOINFOHEADER *) format;
481
482     vih->AvgTimePerFrame = gst_util_uint64_scale_int (10000000, fps_d, fps_n);
483     vih->dwBitRate = dwRate * vih->bmiHeader.biBitCount;
484
485     g_assert (vih->bmiHeader.biWidth == width);
486     g_assert (vih->bmiHeader.biHeight == height);
487   } else if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo2)) {
488     KS_VIDEOINFOHEADER2 *vih = (KS_VIDEOINFOHEADER2 *) format;
489
490     vih->AvgTimePerFrame = gst_util_uint64_scale_int (10000000, fps_d, fps_n);
491     vih->dwBitRate = dwRate * vih->bmiHeader.biBitCount;
492
493     g_assert (vih->bmiHeader.biWidth == width);
494     g_assert (vih->bmiHeader.biHeight == height);
495   } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEGVideo)) {
496     KS_MPEG1VIDEOINFO *vih = (KS_MPEG1VIDEOINFO *) format;
497
498     vih->hdr.AvgTimePerFrame =
499         gst_util_uint64_scale_int (10000000, fps_d, fps_n);
500     vih->hdr.dwBitRate = dwRate * vih->hdr.bmiHeader.biBitCount;
501
502     /* FIXME: set height and width? */
503     g_assert (vih->hdr.bmiHeader.biWidth == width);
504     g_assert (vih->hdr.bmiHeader.biHeight == height);
505   } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEG2Video)) {
506     KS_MPEGVIDEOINFO2 *vih = (KS_MPEGVIDEOINFO2 *) format;
507
508     vih->hdr.AvgTimePerFrame =
509         gst_util_uint64_scale_int (10000000, fps_d, fps_n);
510     vih->hdr.dwBitRate = dwRate * vih->hdr.bmiHeader.biBitCount;
511
512     /* FIXME: set height and width? */
513     g_assert (vih->hdr.bmiHeader.biWidth == width);
514     g_assert (vih->hdr.bmiHeader.biHeight == height);
515   } else {
516     return FALSE;
517   }
518
519   return TRUE;
520 }
521
522 static GstStructure *
523 ks_video_append_var_video_fields (GstStructure * structure)
524 {
525   if (structure) {
526     gst_structure_set (structure,
527         "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
528         "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
529         "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
530   }
531
532   return structure;
533 }
534
535 GstCaps *
536 ks_video_get_all_caps (void)
537 {
538   static GstCaps *caps = NULL;
539
540   if (caps == NULL) {
541     GstStructure *structure;
542     caps = gst_caps_new_empty ();
543
544     /* from Windows SDK 6.0 uuids.h */
545     /* RGB formats */
546     structure =
547         ks_video_append_var_video_fields (ks_video_format_to_structure
548         (MEDIASUBTYPE_RGB555, FORMAT_VideoInfo));
549     gst_caps_append_structure (caps, structure);
550
551     structure =
552         ks_video_append_var_video_fields (ks_video_format_to_structure
553         (MEDIASUBTYPE_RGB565, FORMAT_VideoInfo));
554     gst_caps_append_structure (caps, structure);
555
556     structure =
557         ks_video_append_var_video_fields (ks_video_format_to_structure
558         (MEDIASUBTYPE_RGB24, FORMAT_VideoInfo));
559     gst_caps_append_structure (caps, structure);
560
561     structure =
562         ks_video_append_var_video_fields (ks_video_format_to_structure
563         (MEDIASUBTYPE_RGB32, FORMAT_VideoInfo));
564     gst_caps_append_structure (caps, structure);
565
566     /* YUV formats */
567     structure =
568         ks_video_append_var_video_fields (gst_structure_new ("video/x-raw-yuv",
569             NULL));
570     gst_caps_append_structure (caps, structure);
571
572     /* Other formats */
573     structure =
574         ks_video_append_var_video_fields (ks_video_format_to_structure
575         (MEDIASUBTYPE_MJPG, FORMAT_VideoInfo));
576     gst_caps_append_structure (caps, structure);
577
578     structure =
579         ks_video_append_var_video_fields (ks_video_format_to_structure
580         (MEDIASUBTYPE_dvsd, FORMAT_VideoInfo));
581     gst_caps_append_structure (caps, structure);
582
583     structure =                 /* no variable video fields (width, height, framerate) */
584         ks_video_format_to_structure (MEDIASUBTYPE_dvsd, FORMAT_DvInfo);
585     gst_caps_append_structure (caps, structure);
586   }
587
588   return caps;
589 }