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"
25 #include "kshelpers.h"
27 GST_DEBUG_CATEGORY_EXTERN (gst_ks_debug);
28 #define GST_CAT_DEFAULT gst_ks_debug
30 static const GUID MEDIASUBTYPE_FOURCC =
31 { 0x0 /* FourCC here */ , 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xAA, 0x00,
35 extern const GUID MEDIASUBTYPE_I420 =
36 { 0x30323449, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B,
41 ks_video_format_to_structure (GUID subtype_guid, GUID format_guid)
43 GstStructure *structure = NULL;
45 if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_MJPG) || IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_TVMJ) || /* FIXME: NOT tested */
46 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_WAKE) || /* FIXME: NOT tested */
47 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_CFCC) || /* FIXME: NOT tested */
48 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_IJPG)) { /* FIXME: NOT tested */
49 structure = gst_structure_new ("image/jpeg", NULL);
50 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB555) || /* FIXME: NOT tested */
51 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB565) || /* FIXME: NOT tested */
52 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB24) || IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB32) || /* FIXME: NOT tested */
53 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB1555) || /* FIXME: NOT tested */
54 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB32) || /* FIXME: NOT tested */
55 IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB4444)) { /* FIXME: NOT tested */
56 guint depth = 0, bpp = 0;
58 guint32 r_mask = 0, b_mask = 0, g_mask = 0;
60 if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB555)) {
63 endianness = G_BIG_ENDIAN;
67 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB565)) {
69 endianness = G_BIG_ENDIAN;
73 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB24)) {
75 endianness = G_BIG_ENDIAN;
79 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_RGB32)) {
82 endianness = G_BIG_ENDIAN;
91 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB1555)) {
94 endianness = G_BIG_ENDIAN;
98 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB32)) {
100 endianness = G_BIG_ENDIAN;
105 *r_mask = 0xff000000;
106 *g_mask = 0x00ff0000;
107 *b_mask = 0x0000ff00;
109 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_ARGB4444)) {
112 endianness = G_BIG_ENDIAN;
120 g_assert_not_reached ();
123 structure = gst_structure_new ("video/x-raw-rgb",
124 "bpp", G_TYPE_INT, bpp,
125 "depth", G_TYPE_INT, depth,
126 "red_mask", G_TYPE_INT, r_mask,
127 "green_mask", G_TYPE_INT, g_mask,
128 "blue_mask", G_TYPE_INT, b_mask,
129 "endianness", G_TYPE_INT, endianness, NULL);
130 } else if (IsEqualGUID (&subtype_guid, &MEDIASUBTYPE_dvsd)) {
131 if (IsEqualGUID (&format_guid, &FORMAT_DvInfo)) {
132 structure = gst_structure_new ("video/x-dv",
133 "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
134 } else if (IsEqualGUID (&format_guid, &FORMAT_VideoInfo)) {
135 structure = gst_structure_new ("video/x-dv",
136 "systemstream", G_TYPE_BOOLEAN, FALSE,
137 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('d', 'v', 's', 'd'),
140 } else if (memcmp (&subtype_guid.Data2, &MEDIASUBTYPE_FOURCC.Data2,
141 sizeof (subtype_guid) - sizeof (subtype_guid.Data1)) == 0) {
142 guint8 *p = (guint8 *) & subtype_guid.Data1;
144 structure = gst_structure_new ("video/x-raw-yuv",
145 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC (p[0], p[1], p[2], p[3]),
150 GST_DEBUG ("Unknown DirectShow Video GUID %08x-%04x-%04x-%04x-%08x%04x",
151 subtype_guid.Data1, subtype_guid.Data2, subtype_guid.Data3,
152 *(WORD *) subtype_guid.Data4, *(DWORD *) & subtype_guid.Data4[2],
153 *(WORD *) & subtype_guid.Data4[6]);
160 guess_aspect (gint width, gint height, gint * par_width, gint * par_height)
163 * As we dont have access to the actual pixel aspect, we will try to do a
164 * best-effort guess. The guess is based on most sensors being either 4/3
165 * or 16/9, and most pixel aspects being close to 1/1.
167 if ((width == 768) && (height == 448)) { /* special case for w448p */
171 if (((float) width / (float) height) < 1.2778) {
182 ks_video_append_video_stream_cfg_fields (GstStructure * structure,
183 const KS_VIDEO_STREAM_CONFIG_CAPS * vscc)
185 g_return_val_if_fail (structure, FALSE);
186 g_return_val_if_fail (vscc, FALSE);
189 if (vscc->MinOutputSize.cx == vscc->MaxOutputSize.cx) {
190 gst_structure_set (structure,
191 "width", G_TYPE_INT, vscc->MaxOutputSize.cx, NULL);
193 gst_structure_set (structure,
194 "width", GST_TYPE_INT_RANGE,
195 vscc->MinOutputSize.cx, vscc->MaxOutputSize.cx, NULL);
199 if (vscc->MinOutputSize.cy == vscc->MaxOutputSize.cy) {
200 gst_structure_set (structure,
201 "height", G_TYPE_INT, vscc->MaxOutputSize.cy, NULL);
203 gst_structure_set (structure,
204 "height", GST_TYPE_INT_RANGE,
205 vscc->MinOutputSize.cy, vscc->MaxOutputSize.cy, NULL);
209 if (vscc->MinFrameInterval == vscc->MaxFrameInterval) {
210 gst_structure_set (structure,
211 "framerate", GST_TYPE_FRACTION,
212 (gint) (10000000 / vscc->MaxFrameInterval), 1, NULL);
214 gst_structure_set (structure,
215 "framerate", GST_TYPE_FRACTION_RANGE,
216 (gint) (10000000 / vscc->MaxFrameInterval), 1,
217 (gint) (10000000 / vscc->MinFrameInterval), 1, NULL);
221 gint par_width, par_height;
223 guess_aspect (vscc->MaxOutputSize.cx, vscc->MaxOutputSize.cy,
224 &par_width, &par_height);
226 gst_structure_set (structure,
227 "pixel-aspect-ratio", GST_TYPE_FRACTION, par_width, par_height, NULL);
234 ks_video_media_type_dup (KsVideoMediaType * media_type)
236 KsVideoMediaType *result = g_new (KsVideoMediaType, 1);
238 memcpy (result, media_type, sizeof (KsVideoMediaType));
240 result->range = g_malloc (media_type->range->FormatSize);
241 memcpy ((gpointer) result->range, media_type->range,
242 media_type->range->FormatSize);
244 result->format = g_malloc (media_type->format_size);
245 memcpy (result->format, media_type->format, media_type->format_size);
247 result->translated_caps = gst_caps_ref (media_type->translated_caps);
253 ks_video_media_type_free (KsVideoMediaType * media_type)
255 if (media_type == NULL)
258 g_free ((gpointer) media_type->range);
260 g_free (media_type->format);
262 if (media_type->translated_caps != NULL)
263 gst_caps_unref (media_type->translated_caps);
269 ks_video_media_type_list_remove_duplicates (GList * media_types)
271 GList *master, *duplicates;
276 master = duplicates = NULL;
278 /* Find the first set of duplicates and their master */
279 for (entry = media_types; entry != NULL && duplicates == NULL;
280 entry = entry->next) {
281 KsVideoMediaType *mt = entry->data;
284 for (other_entry = media_types; other_entry != NULL;
285 other_entry = other_entry->next) {
286 KsVideoMediaType *other_mt = other_entry->data;
291 if (gst_caps_is_equal (mt->translated_caps, other_mt->translated_caps))
292 duplicates = g_list_prepend (duplicates, other_mt);
295 if (duplicates != NULL)
299 if (duplicates != NULL) {
300 KsVideoMediaType *selected_mt = master->data;
303 * Pick a FORMAT_VideoInfo2 if present, if not we just stay with the
306 for (entry = duplicates; entry != NULL; entry = entry->next) {
307 KsVideoMediaType *mt = entry->data;
309 if (IsEqualGUID (&mt->range->Specifier, &FORMAT_VideoInfo2)) {
310 ks_video_media_type_free (selected_mt);
313 ks_video_media_type_free (mt);
316 /* Remove the dupe from the main list */
317 media_types = g_list_remove (media_types, mt);
320 /* Update master node with the selected MediaType */
321 master->data = selected_mt;
323 g_list_free (duplicates);
326 while (master != NULL);
332 ks_video_probe_filter_for_caps (HANDLE filter_handle)
338 if (!ks_filter_get_pin_property (filter_handle, 0, KSPROPSETID_Pin,
339 KSPROPERTY_PIN_CTYPES, &pin_count, sizeof (pin_count)))
342 GST_DEBUG ("pin_count = %d", pin_count);
344 for (pin_id = 0; pin_id < pin_count; pin_id++) {
345 KSPIN_COMMUNICATION pin_comm;
346 KSPIN_DATAFLOW pin_flow;
349 if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
350 KSPROPERTY_PIN_COMMUNICATION, &pin_comm, sizeof (pin_comm)))
353 if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
354 KSPROPERTY_PIN_DATAFLOW, &pin_flow, sizeof (pin_flow)))
357 if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
358 KSPROPERTY_PIN_CATEGORY, &pin_cat, sizeof (pin_cat)))
361 GST_DEBUG ("pin[%u]: pin_comm=%d, pin_flow=%d", pin_id, pin_comm, pin_flow);
363 if (pin_flow == KSPIN_DATAFLOW_OUT &&
364 memcmp (&pin_cat, &PINNAME_CAPTURE, sizeof (GUID)) == 0) {
365 KSMULTIPLE_ITEM *items;
367 if (ks_filter_get_pin_property_multi (filter_handle, pin_id,
368 KSPROPSETID_Pin, KSPROPERTY_PIN_DATARANGES, &items)) {
369 KSDATARANGE *range = (KSDATARANGE *) (items + 1);
372 for (i = 0; i < items->Count; i++) {
373 if (IsEqualGUID (&range->MajorFormat, &KSDATAFORMAT_TYPE_VIDEO)) {
374 KsVideoMediaType *entry;
375 gpointer src_vscc, src_format;
376 GstStructure *media_structure;
378 entry = g_new0 (KsVideoMediaType, 1);
379 entry->pin_id = pin_id;
381 entry->range = g_malloc (range->FormatSize);
382 memcpy ((gpointer) entry->range, range, range->FormatSize);
384 if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo)) {
385 KS_DATARANGE_VIDEO *vr = (KS_DATARANGE_VIDEO *) entry->range;
387 src_vscc = &vr->ConfigCaps;
388 src_format = &vr->VideoInfoHeader;
390 entry->format_size = sizeof (vr->VideoInfoHeader);
391 entry->sample_size = vr->VideoInfoHeader.bmiHeader.biSizeImage;
392 } else if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo2)) {
393 KS_DATARANGE_VIDEO2 *vr = (KS_DATARANGE_VIDEO2 *) entry->range;
395 src_vscc = &vr->ConfigCaps;
396 src_format = &vr->VideoInfoHeader;
398 entry->format_size = sizeof (vr->VideoInfoHeader);
399 entry->sample_size = vr->VideoInfoHeader.bmiHeader.biSizeImage;
400 } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEGVideo)) {
401 /* Untested and probably wrong... */
402 KS_DATARANGE_MPEG1_VIDEO *vr =
403 (KS_DATARANGE_MPEG1_VIDEO *) entry->range;
405 src_vscc = &vr->ConfigCaps;
406 src_format = &vr->VideoInfoHeader;
408 entry->format_size = sizeof (vr->VideoInfoHeader);
410 vr->VideoInfoHeader.hdr.bmiHeader.biSizeImage;
411 } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEG2Video)) {
412 /* Untested and probably wrong... */
413 KS_DATARANGE_MPEG2_VIDEO *vr =
414 (KS_DATARANGE_MPEG2_VIDEO *) entry->range;
416 src_vscc = &vr->ConfigCaps;
417 src_format = &vr->VideoInfoHeader;
419 entry->format_size = sizeof (vr->VideoInfoHeader);
421 vr->VideoInfoHeader.hdr.bmiHeader.biSizeImage;
425 guid_str = ks_guid_to_string (&range->Specifier);
426 GST_DEBUG ("pin[%u]: ignoring unknown specifier GUID %s",
430 ks_video_media_type_free (entry);
435 g_assert (entry->sample_size != 0);
437 memcpy ((gpointer) & entry->vscc, src_vscc, sizeof (entry->vscc));
439 entry->format = g_malloc (entry->format_size);
440 memcpy (entry->format, src_format, entry->format_size);
443 ks_video_format_to_structure (range->SubFormat,
446 if (media_structure == NULL) {
447 g_warning ("ks_video_format_to_structure returned NULL");
448 ks_video_media_type_free (entry);
450 } else if (ks_video_append_video_stream_cfg_fields
451 (media_structure, &entry->vscc)) {
452 entry->translated_caps = gst_caps_new_empty ();
453 gst_caps_append_structure (entry->translated_caps,
456 gst_structure_free (media_structure);
457 ks_video_media_type_free (entry);
462 ret = g_list_prepend (ret, entry);
466 /* REVISIT: Each KSDATARANGE should start on a 64-bit boundary */
467 range = (KSDATARANGE *) (((guchar *) range) + range->FormatSize);
476 ret = g_list_reverse (ret);
477 ret = ks_video_media_type_list_remove_duplicates (ret);
485 ks_video_create_pin_conn_from_media_type (KsVideoMediaType * media_type)
487 KSPIN_CONNECT *conn = NULL;
488 KSDATAFORMAT *format = NULL;
491 conn = g_malloc0 (sizeof (KSPIN_CONNECT) + sizeof (KSDATAFORMAT) +
492 media_type->format_size);
494 conn->Interface.Set = KSINTERFACESETID_Standard;
495 conn->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
496 conn->Interface.Flags = 0;
498 conn->Medium.Set = KSMEDIUMSETID_Standard;
499 conn->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
500 conn->Medium.Flags = 0;
502 conn->PinId = media_type->pin_id;
503 conn->PinToHandle = NULL;
504 conn->Priority.PriorityClass = KSPRIORITY_NORMAL;
505 conn->Priority.PrioritySubClass = 1;
507 format = (KSDATAFORMAT *) (conn + 1);
508 memcpy (format, media_type->range, sizeof (KSDATAFORMAT));
509 format->FormatSize = sizeof (KSDATAFORMAT) + media_type->format_size;
511 vih = (guint8 *) (format + 1);
512 memcpy (vih, media_type->format, media_type->format_size);
518 ks_video_fixate_media_type (const KSDATARANGE * range,
519 guint8 * format, gint width, gint height, gint fps_n, gint fps_d)
521 DWORD dwRate = (width * height * fps_n) / fps_d;
523 g_return_val_if_fail (format != NULL, FALSE);
525 if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo)) {
526 KS_VIDEOINFOHEADER *vih = (KS_VIDEOINFOHEADER *) format;
528 /* FIXME: Need to figure out how to properly handle ranges */
529 if (vih->bmiHeader.biWidth != width || vih->bmiHeader.biHeight != height)
532 vih->AvgTimePerFrame = gst_util_uint64_scale_int (10000000, fps_d, fps_n);
533 vih->dwBitRate = dwRate * vih->bmiHeader.biBitCount;
534 } else if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo2)) {
535 KS_VIDEOINFOHEADER2 *vih = (KS_VIDEOINFOHEADER2 *) format;
537 /* FIXME: see above */
538 if (vih->bmiHeader.biWidth != width || vih->bmiHeader.biHeight != height)
541 vih->AvgTimePerFrame = gst_util_uint64_scale_int (10000000, fps_d, fps_n);
542 vih->dwBitRate = dwRate * vih->bmiHeader.biBitCount;
543 } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEGVideo)) {
544 KS_MPEG1VIDEOINFO *vih = (KS_MPEG1VIDEOINFO *) format;
546 /* FIXME: see above */
547 if (vih->hdr.bmiHeader.biWidth != width ||
548 vih->hdr.bmiHeader.biHeight != height)
553 vih->hdr.AvgTimePerFrame =
554 gst_util_uint64_scale_int (10000000, fps_d, fps_n);
555 vih->hdr.dwBitRate = dwRate * vih->hdr.bmiHeader.biBitCount;
556 } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEG2Video)) {
557 KS_MPEGVIDEOINFO2 *vih = (KS_MPEGVIDEOINFO2 *) format;
559 /* FIXME: see above */
560 if (vih->hdr.bmiHeader.biWidth != width ||
561 vih->hdr.bmiHeader.biHeight != height)
566 vih->hdr.AvgTimePerFrame =
567 gst_util_uint64_scale_int (10000000, fps_d, fps_n);
568 vih->hdr.dwBitRate = dwRate * vih->hdr.bmiHeader.biBitCount;
576 static GstStructure *
577 ks_video_append_var_video_fields (GstStructure * structure)
580 gst_structure_set (structure,
581 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
582 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
583 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
590 ks_video_get_all_caps (void)
592 static GstCaps *caps = NULL;
595 GstStructure *structure;
596 caps = gst_caps_new_empty ();
598 /* from Windows SDK 6.0 uuids.h */
601 ks_video_append_var_video_fields (ks_video_format_to_structure
602 (MEDIASUBTYPE_RGB555, FORMAT_VideoInfo));
603 gst_caps_append_structure (caps, structure);
606 ks_video_append_var_video_fields (ks_video_format_to_structure
607 (MEDIASUBTYPE_RGB565, FORMAT_VideoInfo));
608 gst_caps_append_structure (caps, structure);
611 ks_video_append_var_video_fields (ks_video_format_to_structure
612 (MEDIASUBTYPE_RGB24, FORMAT_VideoInfo));
613 gst_caps_append_structure (caps, structure);
616 ks_video_append_var_video_fields (ks_video_format_to_structure
617 (MEDIASUBTYPE_RGB32, FORMAT_VideoInfo));
618 gst_caps_append_structure (caps, structure);
622 ks_video_append_var_video_fields (gst_structure_new ("video/x-raw-yuv",
624 gst_caps_append_structure (caps, structure);
628 ks_video_append_var_video_fields (ks_video_format_to_structure
629 (MEDIASUBTYPE_MJPG, FORMAT_VideoInfo));
630 gst_caps_append_structure (caps, structure);
633 ks_video_append_var_video_fields (ks_video_format_to_structure
634 (MEDIASUBTYPE_dvsd, FORMAT_VideoInfo));
635 gst_caps_append_structure (caps, structure);
637 structure = /* no variable video fields (width, height, framerate) */
638 ks_video_format_to_structure (MEDIASUBTYPE_dvsd, FORMAT_DvInfo);
639 gst_caps_append_structure (caps, structure);