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>
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.
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.
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.
22 #include "ksvideohelpers.h"
26 #include "kshelpers.h"
28 GST_DEBUG_CATEGORY_EXTERN (gst_ks_debug);
29 #define GST_CAT_DEFAULT gst_ks_debug
31 static const GUID MEDIASUBTYPE_FOURCC =
32 { 0x0 /* FourCC here */ , 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xAA, 0x00,
36 typedef struct _KsVideoDeviceEntry KsVideoDeviceEntry;
38 struct _KsVideoDeviceEntry
40 KsDeviceEntry *device;
45 ks_video_device_entry_decide_priority (KsVideoDeviceEntry * videodevice)
49 videodevice->priority = 0;
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;
58 if (ks_object_get_supported_property_sets (filter_handle, &propsets,
62 for (i = 0; i < propsets_len; i++) {
63 if (memcmp (&propsets[i], &PROPSETID_VIDCAP_CAMERACONTROL,
64 sizeof (GUID)) == 0) {
65 videodevice->priority++;
74 CloseHandle (filter_handle);
78 ks_video_device_entry_compare (gconstpointer a, gconstpointer b)
80 const KsVideoDeviceEntry *videodevice_a = a;
81 const KsVideoDeviceEntry *videodevice_b = b;
83 if (videodevice_a->priority > videodevice_b->priority)
85 else if (videodevice_a->priority == videodevice_b->priority)
92 ks_video_device_list_sort_cameras_first (GList * devices)
94 GList *videodevices = NULL, *walk;
97 for (walk = devices; walk != NULL; walk = walk->next) {
98 KsDeviceEntry *device = walk->data;
99 KsVideoDeviceEntry *videodevice;
101 videodevice = g_new (KsVideoDeviceEntry, 1);
102 videodevice->device = device;
103 ks_video_device_entry_decide_priority (videodevice);
105 videodevices = g_list_append (videodevices, videodevice);
108 videodevices = g_list_sort (videodevices, ks_video_device_entry_compare);
110 g_list_free (devices);
113 for (walk = videodevices, i = 0; walk != NULL; walk = walk->next, i++) {
114 KsVideoDeviceEntry *videodevice = walk->data;
116 videodevice->device->index = i;
117 devices = g_list_append (devices, videodevice->device);
119 g_free (videodevice);
122 g_list_free (videodevices);
127 static GstStructure *
128 ks_video_format_to_structure (GUID subtype_guid, GUID format_guid)
130 GstStructure *structure = NULL;
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;
145 guint32 r_mask = 0, b_mask = 0, g_mask = 0;
147 if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB555)) {
150 endianness = G_BIG_ENDIAN;
154 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB565)) {
156 endianness = G_BIG_ENDIAN;
160 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB24)) {
162 endianness = G_BIG_ENDIAN;
166 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB32)) {
169 endianness = G_BIG_ENDIAN;
174 *r_mask = 0xff000000;
175 *g_mask = 0x00ff0000;
176 *b_mask = 0x0000ff00;
178 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB1555)) {
181 endianness = G_BIG_ENDIAN;
185 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB32)) {
187 endianness = G_BIG_ENDIAN;
192 *r_mask = 0xff000000;
193 *g_mask = 0x00ff0000;
194 *b_mask = 0x0000ff00;
196 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB4444)) {
199 endianness = G_BIG_ENDIAN;
207 g_assert_not_reached ();
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'),
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;
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]),
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]);
247 guess_aspect (gint width, gint height, gint * par_width, gint * par_height)
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.
254 if ((width == 768) && (height == 448)) { /* special case for w448p */
258 if (((float) width / (float) height) < 1.2778) {
268 /* NOTE: would probably be better to use a continued fractions approach here */
270 compress_fraction (gint64 in_num, gint64 in_den, gint64 * out_num,
273 gdouble on, od, orig;
274 guint denominators[] = { 1, 2, 3, 5, 7 }, i;
275 const gdouble max_loss = 0.1;
281 for (i = 0; i < G_N_ELEMENTS (denominators); i++) {
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);
290 if (loss <= max_loss) {
303 ks_video_append_video_stream_cfg_fields (GstStructure * structure,
304 const KS_VIDEO_STREAM_CONFIG_CAPS * vscc)
310 g_return_val_if_fail (structure, FALSE);
311 g_return_val_if_fail (vscc, FALSE);
314 if (vscc->MinOutputSize.cx == vscc->MaxOutputSize.cx) {
315 gst_structure_set (structure,
316 "width", G_TYPE_INT, vscc->MaxOutputSize.cx, NULL);
318 gst_structure_set (structure,
319 "width", GST_TYPE_INT_RANGE,
320 vscc->MinOutputSize.cx, vscc->MaxOutputSize.cx, NULL);
324 if (vscc->MinOutputSize.cy == vscc->MaxOutputSize.cy) {
325 gst_structure_set (structure,
326 "height", G_TYPE_INT, vscc->MaxOutputSize.cy, NULL);
328 gst_structure_set (structure,
329 "height", GST_TYPE_INT_RANGE,
330 vscc->MinOutputSize.cy, vscc->MaxOutputSize.cy, NULL);
334 compress_fraction (NANOSECONDS, vscc->MinFrameInterval, &min_n, &min_d);
335 compress_fraction (NANOSECONDS, vscc->MaxFrameInterval, &max_n, &max_d);
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);
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);
345 gst_structure_set_value (structure, "framerate", &val);
346 g_value_unset (&val);
349 gint par_width, par_height;
351 guess_aspect (vscc->MaxOutputSize.cx, vscc->MaxOutputSize.cy,
352 &par_width, &par_height);
354 gst_structure_set (structure,
355 "pixel-aspect-ratio", GST_TYPE_FRACTION, par_width, par_height, NULL);
362 ks_video_media_type_dup (KsVideoMediaType * media_type)
364 KsVideoMediaType *result = g_new (KsVideoMediaType, 1);
366 memcpy (result, media_type, sizeof (KsVideoMediaType));
368 result->range = g_malloc (media_type->range->FormatSize);
369 memcpy ((gpointer) result->range, media_type->range,
370 media_type->range->FormatSize);
372 result->format = g_malloc (media_type->format_size);
373 memcpy (result->format, media_type->format, media_type->format_size);
375 result->translated_caps = gst_caps_ref (media_type->translated_caps);
381 ks_video_media_type_free (KsVideoMediaType * media_type)
383 if (media_type == NULL)
386 g_free ((gpointer) media_type->range);
388 g_free (media_type->format);
390 if (media_type->translated_caps != NULL)
391 gst_caps_unref (media_type->translated_caps);
397 ks_video_media_type_list_remove_duplicates (GList * media_types)
399 GList *master, *duplicates;
404 master = duplicates = NULL;
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;
412 for (other_entry = media_types; other_entry != NULL;
413 other_entry = other_entry->next) {
414 KsVideoMediaType *other_mt = other_entry->data;
419 if (gst_caps_is_equal (mt->translated_caps, other_mt->translated_caps))
420 duplicates = g_list_prepend (duplicates, other_mt);
423 if (duplicates != NULL)
427 if (duplicates != NULL) {
428 KsVideoMediaType *selected_mt = master->data;
431 * Pick a FORMAT_VideoInfo2 if present, if not we just stay with the
434 for (entry = duplicates; entry != NULL; entry = entry->next) {
435 KsVideoMediaType *mt = entry->data;
437 if (IsEqualGUID (&mt->range->Specifier, &FORMAT_VideoInfo2)) {
438 ks_video_media_type_free (selected_mt);
441 ks_video_media_type_free (mt);
444 /* Remove the dupe from the main list */
445 media_types = g_list_remove (media_types, mt);
448 /* Update master node with the selected MediaType */
449 master->data = selected_mt;
451 g_list_free (duplicates);
454 while (master != NULL);
460 ks_video_probe_filter_for_caps (HANDLE filter_handle)
466 if (!ks_filter_get_pin_property (filter_handle, 0, KSPROPSETID_Pin,
467 KSPROPERTY_PIN_CTYPES, &pin_count, sizeof (pin_count), NULL))
470 GST_DEBUG ("pin_count = %lu", pin_count);
472 for (pin_id = 0; pin_id < pin_count; pin_id++) {
473 KSPIN_COMMUNICATION pin_comm;
474 KSPIN_DATAFLOW pin_flow;
477 if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
478 KSPROPERTY_PIN_COMMUNICATION, &pin_comm, sizeof (pin_comm), NULL))
481 if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
482 KSPROPERTY_PIN_DATAFLOW, &pin_flow, sizeof (pin_flow), NULL))
485 if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
486 KSPROPERTY_PIN_CATEGORY, &pin_cat, sizeof (pin_cat), NULL))
489 GST_DEBUG ("pin[%u]: pin_comm=%d, pin_flow=%d", pin_id, pin_comm, pin_flow);
491 if (pin_flow == KSPIN_DATAFLOW_OUT &&
492 memcmp (&pin_cat, &PINNAME_CAPTURE, sizeof (GUID)) == 0) {
493 KSMULTIPLE_ITEM *items;
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);
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;
506 entry = g_new0 (KsVideoMediaType, 1);
507 entry->pin_id = pin_id;
509 entry->range = g_malloc (range->FormatSize);
510 memcpy ((gpointer) entry->range, range, range->FormatSize);
512 if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo)) {
513 KS_DATARANGE_VIDEO *vr = (KS_DATARANGE_VIDEO *) entry->range;
515 src_vscc = &vr->ConfigCaps;
516 src_format = &vr->VideoInfoHeader;
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;
523 src_vscc = &vr->ConfigCaps;
524 src_format = &vr->VideoInfoHeader;
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;
533 src_vscc = &vr->ConfigCaps;
534 src_format = &vr->VideoInfoHeader;
536 entry->format_size = sizeof (vr->VideoInfoHeader);
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;
544 src_vscc = &vr->ConfigCaps;
545 src_format = &vr->VideoInfoHeader;
547 entry->format_size = sizeof (vr->VideoInfoHeader);
549 vr->VideoInfoHeader.hdr.bmiHeader.biSizeImage;
553 guid_str = ks_guid_to_string (&range->Specifier);
554 GST_DEBUG ("pin[%u]: ignoring unknown specifier GUID %s",
558 ks_video_media_type_free (entry);
563 g_assert (entry->sample_size != 0);
565 memcpy ((gpointer) & entry->vscc, src_vscc, sizeof (entry->vscc));
567 entry->format = g_malloc (entry->format_size);
568 memcpy (entry->format, src_format, entry->format_size);
571 ks_video_format_to_structure (range->SubFormat,
574 if (media_structure == NULL) {
575 g_warning ("ks_video_format_to_structure returned NULL");
576 ks_video_media_type_free (entry);
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,
584 gst_structure_free (media_structure);
585 ks_video_media_type_free (entry);
590 ret = g_list_prepend (ret, entry);
594 /* REVISIT: Each KSDATARANGE should start on a 64-bit boundary */
595 range = (KSDATARANGE *) (((guchar *) range) + range->FormatSize);
604 ret = g_list_reverse (ret);
605 ret = ks_video_media_type_list_remove_duplicates (ret);
613 ks_video_create_pin_conn_from_media_type (KsVideoMediaType * media_type)
615 KSPIN_CONNECT *conn = NULL;
616 KSDATAFORMAT *format = NULL;
619 conn = g_malloc0 (sizeof (KSPIN_CONNECT) + sizeof (KSDATAFORMAT) +
620 media_type->format_size);
622 conn->Interface.Set = KSINTERFACESETID_Standard;
623 conn->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
624 conn->Interface.Flags = 0;
626 conn->Medium.Set = KSMEDIUMSETID_Standard;
627 conn->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
628 conn->Medium.Flags = 0;
630 conn->PinId = media_type->pin_id;
631 conn->PinToHandle = NULL;
632 conn->Priority.PriorityClass = KSPRIORITY_NORMAL;
633 conn->Priority.PrioritySubClass = KSPRIORITY_NORMAL;
635 format = (KSDATAFORMAT *) (conn + 1);
636 memcpy (format, media_type->range, sizeof (KSDATAFORMAT));
637 format->FormatSize = sizeof (KSDATAFORMAT) + media_type->format_size;
639 vih = (guint8 *) (format + 1);
640 memcpy (vih, media_type->format, media_type->format_size);
646 ks_video_fixate_media_type (const KSDATARANGE * range,
647 guint8 * format, gint width, gint height, gint fps_n, gint fps_d)
649 KS_DATARANGE_VIDEO *vr;
650 KS_VIDEOINFOHEADER *vih;
651 KS_BITMAPINFOHEADER *bih;
654 g_return_val_if_fail (format != NULL, FALSE);
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;
668 /* These formats' structures share the most basic stuff */
669 vr = (KS_DATARANGE_VIDEO *) range;
670 vih = (KS_VIDEOINFOHEADER *) format;
672 /* FIXME: Need to figure out how to properly handle ranges */
673 if (bih->biWidth != width || bih->biHeight != height)
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);
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);
693 static GstStructure *
694 ks_video_append_var_video_fields (GstStructure * 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);
707 ks_video_get_all_caps (void)
709 static GstCaps *caps = NULL;
712 GstStructure *structure;
713 caps = gst_caps_new_empty ();
715 /* from Windows SDK 6.0 uuids.h */
718 ks_video_append_var_video_fields (ks_video_format_to_structure
719 (MEDIASUBTYPE_RGB555, FORMAT_VideoInfo));
720 gst_caps_append_structure (caps, 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);
728 ks_video_append_var_video_fields (ks_video_format_to_structure
729 (MEDIASUBTYPE_RGB24, FORMAT_VideoInfo));
730 gst_caps_append_structure (caps, 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);
739 ks_video_append_var_video_fields (gst_structure_new ("video/x-raw-yuv",
741 gst_caps_append_structure (caps, 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);
750 ks_video_append_var_video_fields (ks_video_format_to_structure
751 (MEDIASUBTYPE_dvsd, FORMAT_VideoInfo));
752 gst_caps_append_structure (caps, structure);
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);