2 * Copyright (C) 2007 Haakon Sporsheim <hakon.sporsheim@tandberg.com>
3 * 2008 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
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.
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.
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.
21 #include "ksvideohelpers.h"
24 #include "kshelpers.h"
26 GST_DEBUG_CATEGORY_EXTERN (gst_ks_debug);
27 #define GST_CAT_DEFAULT gst_ks_debug
29 static const GUID MEDIASUBTYPE_FOURCC =
30 { 0x0 /* FourCC here */ , 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xAA, 0x00,
33 extern const GUID MEDIASUBTYPE_I420 =
34 { 0x30323449, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B,
38 ks_video_format_to_structure (GUID subtype_guid, GUID format_guid)
40 GstStructure *structure = NULL;
42 if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_MJPG) || IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_TVMJ) || /* FIXME: NOT tested */
43 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_WAKE) || /* FIXME: NOT tested */
44 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_CFCC) || /* FIXME: NOT tested */
45 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_IJPG)) { /* FIXME: NOT tested */
46 structure = gst_structure_new ("image/jpeg", NULL);
47 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB555) || /* FIXME: NOT tested */
48 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB565) || /* FIXME: NOT tested */
49 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB24) || IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB32) || /* FIXME: NOT tested */
50 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB1555) || /* FIXME: NOT tested */
51 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB32) || /* FIXME: NOT tested */
52 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB4444)) { /* FIXME: NOT tested */
53 guint depth = 0, bpp = 0;
55 guint32 r_mask = 0, b_mask = 0, g_mask = 0;
57 if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB555)) {
60 endianness = G_BIG_ENDIAN;
64 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB565)) {
66 endianness = G_BIG_ENDIAN;
70 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB24)) {
72 endianness = G_BIG_ENDIAN;
76 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB32)) {
79 endianness = G_BIG_ENDIAN;
88 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB1555)) {
91 endianness = G_BIG_ENDIAN;
95 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB32)) {
97 endianness = G_BIG_ENDIAN;
102 *r_mask = 0xff000000;
103 *g_mask = 0x00ff0000;
104 *b_mask = 0x0000ff00;
106 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB4444)) {
109 endianness = G_BIG_ENDIAN;
117 g_assert_not_reached ();
120 structure = gst_structure_new ("video/x-raw-rgb",
121 "bpp", G_TYPE_INT, bpp,
122 "depth", G_TYPE_INT, depth,
123 "red_mask", G_TYPE_INT, r_mask,
124 "green_mask", G_TYPE_INT, g_mask,
125 "blue_mask", G_TYPE_INT, b_mask,
126 "endianness", G_TYPE_INT, endianness, NULL);
127 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_dvsd)) {
128 if (IsEqualGUID (&format_guid, &FORMAT_DvInfo)) {
129 structure = gst_structure_new ("video/x-dv",
130 "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
131 } else if (IsEqualGUID (&format_guid, &FORMAT_VideoInfo)) {
132 structure = gst_structure_new ("video/x-dv",
133 "systemstream", G_TYPE_BOOLEAN, FALSE,
134 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('d', 'v', 's', 'd'),
137 } else if (memcmp (&subtype_guid.Data2, &MEDIASUBTYPE_FOURCC.Data2,
138 sizeof (subtype_guid) - sizeof (subtype_guid.Data1)) == 0) {
139 guint8 *p = (guint8 *) & subtype_guid.Data1;
141 structure = gst_structure_new ("video/x-raw-yuv",
142 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC (p[0], p[1], p[2], p[3]),
147 GST_DEBUG ("Unknown DirectShow Video GUID %08x-%04x-%04x-%04x-%08x%04x",
148 subtype_guid.Data1, subtype_guid.Data2, subtype_guid.Data3,
149 *(WORD *) subtype_guid.Data4, *(DWORD *) & subtype_guid.Data4[2],
150 *(WORD *) & subtype_guid.Data4[6]);
157 ks_video_append_video_stream_cfg_fields (GstStructure * structure,
158 const KS_VIDEO_STREAM_CONFIG_CAPS * vscc)
160 g_return_val_if_fail (structure, FALSE);
161 g_return_val_if_fail (vscc, FALSE);
164 if (vscc->MinOutputSize.cx == vscc->MaxOutputSize.cx) {
165 gst_structure_set (structure,
166 "width", G_TYPE_INT, vscc->MaxOutputSize.cx, NULL);
168 gst_structure_set (structure,
169 "width", GST_TYPE_INT_RANGE,
170 vscc->MinOutputSize.cx, vscc->MaxOutputSize.cx, NULL);
174 if (vscc->MinOutputSize.cy == vscc->MaxOutputSize.cy) {
175 gst_structure_set (structure,
176 "height", G_TYPE_INT, vscc->MaxOutputSize.cy, NULL);
178 gst_structure_set (structure,
179 "height", GST_TYPE_INT_RANGE,
180 vscc->MinOutputSize.cy, vscc->MaxOutputSize.cy, NULL);
184 if (vscc->MinFrameInterval == vscc->MaxFrameInterval) {
185 gst_structure_set (structure,
186 "framerate", GST_TYPE_FRACTION,
187 (gint) (10000000 / vscc->MaxFrameInterval), 1, NULL);
189 gst_structure_set (structure,
190 "framerate", GST_TYPE_FRACTION_RANGE,
191 (gint) (10000000 / vscc->MaxFrameInterval), 1,
192 (gint) (10000000 / vscc->MinFrameInterval), 1, NULL);
199 ks_video_media_type_dup (KsVideoMediaType * media_type)
201 KsVideoMediaType *result = g_new (KsVideoMediaType, 1);
203 memcpy (result, media_type, sizeof (KsVideoMediaType));
205 result->range = g_malloc (media_type->range->FormatSize);
206 memcpy ((gpointer) result->range, media_type->range,
207 media_type->range->FormatSize);
209 result->format = g_malloc (media_type->format_size);
210 memcpy (result->format, media_type->format, media_type->format_size);
212 result->translated_caps = gst_caps_ref (media_type->translated_caps);
218 ks_video_media_type_free (KsVideoMediaType * media_type)
220 if (media_type == NULL)
223 g_free (media_type->format);
225 if (media_type->translated_caps != NULL)
226 gst_caps_unref (media_type->translated_caps);
232 ks_video_media_type_list_remove_duplicates (GList * media_types)
234 GList *master, *duplicates;
239 master = duplicates = NULL;
241 /* Find the first set of duplicates and their master */
242 for (entry = media_types; entry != NULL && duplicates == NULL;
243 entry = entry->next) {
244 KsVideoMediaType *mt = entry->data;
247 for (other_entry = media_types; other_entry != NULL;
248 other_entry = other_entry->next) {
249 KsVideoMediaType *other_mt = other_entry->data;
254 if (gst_caps_is_equal (mt->translated_caps, other_mt->translated_caps))
255 duplicates = g_list_prepend (duplicates, other_mt);
258 if (duplicates != NULL)
262 if (duplicates != NULL) {
263 KsVideoMediaType *selected_mt = master->data;
266 * Pick a FORMAT_VideoInfo2 if present, if not we just stay with the
269 for (entry = duplicates; entry != NULL; entry = entry->next) {
270 KsVideoMediaType *mt = entry->data;
272 if (IsEqualGUID (&mt->range->Specifier, &FORMAT_VideoInfo2)) {
273 ks_video_media_type_free (selected_mt);
276 ks_video_media_type_free (mt);
279 /* Remove the dupe from the main list */
280 media_types = g_list_remove (media_types, mt);
283 /* Update master node with the selected MediaType */
284 master->data = selected_mt;
286 g_list_free (duplicates);
289 while (master != NULL);
295 ks_video_probe_filter_for_caps (HANDLE filter_handle)
301 if (!ks_filter_get_pin_property (filter_handle, 0, KSPROPSETID_Pin,
302 KSPROPERTY_PIN_CTYPES, &pin_count, sizeof (pin_count)))
305 GST_DEBUG ("pin_count = %d", pin_count);
307 for (pin_id = 0; pin_id < pin_count; pin_id++) {
308 KSPIN_COMMUNICATION pin_comm;
309 KSPIN_DATAFLOW pin_flow;
312 if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
313 KSPROPERTY_PIN_COMMUNICATION, &pin_comm, sizeof (pin_comm)))
316 if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
317 KSPROPERTY_PIN_DATAFLOW, &pin_flow, sizeof (pin_flow)))
320 if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
321 KSPROPERTY_PIN_CATEGORY, &pin_cat, sizeof (pin_cat)))
324 GST_DEBUG ("pin[%d]: pin_comm=%d, pin_flow=%d", pin_id, pin_comm, pin_flow);
326 if (pin_flow == KSPIN_DATAFLOW_OUT &&
327 memcmp (&pin_cat, &PINNAME_CAPTURE, sizeof (GUID)) == 0) {
328 KSMULTIPLE_ITEM *items;
330 if (ks_filter_get_pin_property_multi (filter_handle, pin_id,
331 KSPROPSETID_Pin, KSPROPERTY_PIN_DATARANGES, &items)) {
332 KSDATARANGE *range = (KSDATARANGE *) (items + 1);
335 for (i = 0; i < items->Count; i++) {
336 if (IsEqualGUID (&range->MajorFormat, &KSDATAFORMAT_TYPE_VIDEO)) {
337 KsVideoMediaType *entry;
338 gpointer src_vscc, src_format;
339 GstStructure *media_structure;
341 entry = g_new0 (KsVideoMediaType, 1);
342 entry->pin_id = pin_id;
344 entry->range = g_malloc (range->FormatSize);
345 memcpy ((gpointer) entry->range, range, range->FormatSize);
347 if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo)) {
348 KS_DATARANGE_VIDEO *vr = (KS_DATARANGE_VIDEO *) entry->range;
350 src_vscc = &vr->ConfigCaps;
351 src_format = &vr->VideoInfoHeader;
353 entry->format_size = sizeof (vr->VideoInfoHeader);
354 entry->sample_size = vr->VideoInfoHeader.bmiHeader.biSizeImage;
355 } else if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo2)) {
356 KS_DATARANGE_VIDEO2 *vr = (KS_DATARANGE_VIDEO2 *) entry->range;
358 src_vscc = &vr->ConfigCaps;
359 src_format = &vr->VideoInfoHeader;
361 entry->format_size = sizeof (vr->VideoInfoHeader);
362 entry->sample_size = vr->VideoInfoHeader.bmiHeader.biSizeImage;
363 } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEGVideo)) {
364 /* Untested and probably wrong... */
365 KS_DATARANGE_MPEG1_VIDEO *vr =
366 (KS_DATARANGE_MPEG1_VIDEO *) entry->range;
368 src_vscc = &vr->ConfigCaps;
369 src_format = &vr->VideoInfoHeader;
371 entry->format_size = sizeof (vr->VideoInfoHeader);
373 vr->VideoInfoHeader.hdr.bmiHeader.biSizeImage;
374 } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEG2Video)) {
375 /* Untested and probably wrong... */
376 KS_DATARANGE_MPEG2_VIDEO *vr =
377 (KS_DATARANGE_MPEG2_VIDEO *) entry->range;
379 src_vscc = &vr->ConfigCaps;
380 src_format = &vr->VideoInfoHeader;
382 entry->format_size = sizeof (vr->VideoInfoHeader);
384 vr->VideoInfoHeader.hdr.bmiHeader.biSizeImage;
386 g_assert_not_reached ();
388 g_assert (entry->sample_size != 0);
390 memcpy ((gpointer) & entry->vscc, src_vscc, sizeof (entry->vscc));
392 entry->format = g_malloc (entry->format_size);
393 memcpy (entry->format, src_format, entry->format_size);
396 ks_video_format_to_structure (range->SubFormat,
399 if (media_structure == NULL) {
400 g_warning ("ks_video_format_to_structure returned NULL");
401 ks_video_media_type_free (entry);
403 } else if (ks_video_append_video_stream_cfg_fields (media_structure,
405 entry->translated_caps = gst_caps_new_empty ();
406 gst_caps_append_structure (entry->translated_caps,
409 gst_structure_free (media_structure);
410 ks_video_media_type_free (entry);
415 ret = g_list_prepend (ret, entry);
418 /* REVISIT: Each KSDATARANGE should start on a 64-bit boundary */
419 range = (KSDATARANGE *) (((guchar *) range) + range->FormatSize);
426 ret = g_list_reverse (ret);
427 ret = ks_video_media_type_list_remove_duplicates (ret);
435 ks_video_create_pin_conn_from_media_type (KsVideoMediaType * media_type)
437 KSPIN_CONNECT *conn = NULL;
438 KSDATAFORMAT *format = NULL;
441 conn = g_malloc0 (sizeof (KSPIN_CONNECT) + sizeof (KSDATAFORMAT) +
442 media_type->format_size);
444 conn->Interface.Set = KSINTERFACESETID_Standard;
445 conn->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
446 conn->Interface.Flags = 0;
448 conn->Medium.Set = KSMEDIUMSETID_Standard;
449 conn->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
450 conn->Medium.Flags = 0;
452 conn->PinId = media_type->pin_id;
453 conn->PinToHandle = NULL;
454 conn->Priority.PriorityClass = KSPRIORITY_NORMAL;
455 conn->Priority.PrioritySubClass = 1;
457 format = (KSDATAFORMAT *) (conn + 1);
458 memcpy (format, media_type->range, sizeof (KSDATAFORMAT));
459 format->FormatSize = sizeof (KSDATAFORMAT) + media_type->format_size;
461 vih = (guint8 *) (format + 1);
462 memcpy (vih, media_type->format, media_type->format_size);
468 ks_video_fixate_media_type (const KSDATARANGE * range,
469 guint8 * format, gint width, gint height, gint fps_n, gint fps_d)
471 DWORD dwRate = (width * height * fps_n) / fps_d;
473 g_return_val_if_fail (format != NULL, FALSE);
475 if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo)) {
476 KS_VIDEOINFOHEADER *vih = (KS_VIDEOINFOHEADER *) format;
478 vih->AvgTimePerFrame = gst_util_uint64_scale_int (10000000, fps_d, fps_n);
479 vih->dwBitRate = dwRate * vih->bmiHeader.biBitCount;
481 g_assert (vih->bmiHeader.biWidth == width);
482 g_assert (vih->bmiHeader.biHeight == height);
483 } else if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo2)) {
484 KS_VIDEOINFOHEADER2 *vih = (KS_VIDEOINFOHEADER2 *) format;
486 vih->AvgTimePerFrame = gst_util_uint64_scale_int (10000000, fps_d, fps_n);
487 vih->dwBitRate = dwRate * vih->bmiHeader.biBitCount;
489 g_assert (vih->bmiHeader.biWidth == width);
490 g_assert (vih->bmiHeader.biHeight == height);
491 } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEGVideo)) {
492 KS_MPEG1VIDEOINFO *vih = (KS_MPEG1VIDEOINFO *) format;
494 vih->hdr.AvgTimePerFrame =
495 gst_util_uint64_scale_int (10000000, fps_d, fps_n);
496 vih->hdr.dwBitRate = dwRate * vih->hdr.bmiHeader.biBitCount;
498 /* FIXME: set height and width? */
499 g_assert (vih->hdr.bmiHeader.biWidth == width);
500 g_assert (vih->hdr.bmiHeader.biHeight == height);
501 } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEG2Video)) {
502 KS_MPEGVIDEOINFO2 *vih = (KS_MPEGVIDEOINFO2 *) format;
504 vih->hdr.AvgTimePerFrame =
505 gst_util_uint64_scale_int (10000000, fps_d, fps_n);
506 vih->hdr.dwBitRate = dwRate * vih->hdr.bmiHeader.biBitCount;
508 /* FIXME: set height and width? */
509 g_assert (vih->hdr.bmiHeader.biWidth == width);
510 g_assert (vih->hdr.bmiHeader.biHeight == height);
518 static GstStructure *
519 ks_video_append_var_video_fields (GstStructure * structure)
522 gst_structure_set (structure,
523 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
524 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
525 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
532 ks_video_get_all_caps (void)
534 static GstCaps *caps = NULL;
537 GstStructure *structure;
538 caps = gst_caps_new_empty ();
540 /* from Windows SDK 6.0 uuids.h */
543 ks_video_append_var_video_fields (ks_video_format_to_structure
544 (MEDIASUBTYPE_RGB555, FORMAT_VideoInfo));
545 gst_caps_append_structure (caps, structure);
548 ks_video_append_var_video_fields (ks_video_format_to_structure
549 (MEDIASUBTYPE_RGB565, FORMAT_VideoInfo));
550 gst_caps_append_structure (caps, structure);
553 ks_video_append_var_video_fields (ks_video_format_to_structure
554 (MEDIASUBTYPE_RGB24, FORMAT_VideoInfo));
555 gst_caps_append_structure (caps, structure);
558 ks_video_append_var_video_fields (ks_video_format_to_structure
559 (MEDIASUBTYPE_RGB32, FORMAT_VideoInfo));
560 gst_caps_append_structure (caps, structure);
564 ks_video_append_var_video_fields (gst_structure_new ("video/x-raw-yuv",
566 gst_caps_append_structure (caps, structure);
570 ks_video_append_var_video_fields (ks_video_format_to_structure
571 (MEDIASUBTYPE_MJPG, FORMAT_VideoInfo));
572 gst_caps_append_structure (caps, structure);
575 ks_video_append_var_video_fields (ks_video_format_to_structure
576 (MEDIASUBTYPE_dvsd, FORMAT_VideoInfo));
577 gst_caps_append_structure (caps, structure);
579 structure = /* no variable video fields (width, height, framerate) */
580 ks_video_format_to_structure (MEDIASUBTYPE_dvsd, FORMAT_DvInfo);
581 gst_caps_append_structure (caps, structure);