2007-01-09 Tim-Philipp Müller <tim at centricular dot net>
+ * configure.ac:
+ * gst-libs/gst/Makefile.am:
+ * gst-libs/gst/utils/Makefile.am:
+ * gst-libs/gst/utils/base-utils.c: (gst_base_utils_init):
+ * gst-libs/gst/utils/base-utils.h:
+ * gst-libs/gst/utils/descriptions.c: (format_info_get_desc),
+ (find_format_info), (caps_are_rtp_caps),
+ (gst_base_utils_get_source_description),
+ (gst_base_utils_get_sink_description),
+ (gst_base_utils_get_decoder_description),
+ (gst_base_utils_get_encoder_description),
+ (gst_base_utils_get_element_description),
+ (gst_base_utils_add_codec_description_to_tag_list),
+ (gst_base_utils_get_codec_description), (gst_base_utils_list_all):
+ * gst-libs/gst/utils/descriptions.h:
+ * gst-libs/gst/utils/missing-plugins.c:
+ (missing_structure_get_type), (copy_and_clean_caps),
+ (gst_missing_uri_source_message_new),
+ (gst_missing_uri_sink_message_new),
+ (gst_missing_element_message_new),
+ (gst_missing_decoder_message_new),
+ (gst_missing_encoder_message_new),
+ (missing_structure_get_string_detail),
+ (missing_structure_get_caps_detail),
+ (gst_missing_plugin_message_get_installer_detail),
+ (gst_missing_plugin_message_get_description),
+ (gst_is_missing_plugin_message):
+ * gst-libs/gst/utils/missing-plugins.h:
+ API: add new libgstbaseutils library with functions
+ - to create and parse missing-plugins messages
+ - that provide (translated) descriptions for caps/decoders/sources/etc.
+ Closes #392393.
+
+ * pkgconfig/gstreamer-plugins-base-uninstalled.pc.in:
+ * pkgconfig/gstreamer-plugins-base.pc.in:
+ Add new lib.
+
+ * docs/libs/gst-plugins-base-libs-docs.sgml:
+ * docs/libs/gst-plugins-base-libs-sections.txt:
+ Generate docs for new lib and API.
+
+ * tests/check/Makefile.am:
+ * tests/check/libs/.cvsignore:
+ * tests/check/libs/utils.c: (missing_msg_check_getters),
+ (GST_START_TEST), (libgstbaseutils_suite):
+ Add some basic unit tests.
+
+2007-01-09 Tim-Philipp Müller <tim at centricular dot net>
+
* ext/ogg/Makefile.am:
Dist gstoggdemux.h to fix 'make distcheck'.
HAVE_SYS_SOCKET_H="yes", HAVE_SYS_SOCKET_H="no")
AM_CONDITIONAL(HAVE_SYS_SOCKET_H, test "x$HAVE_SYS_SOCKET_H" = "xyes")
+dnl used in gst-libs/gst/utils
+AC_CHECK_HEADERS([process.h])
+
dnl ffmpegcolorspace includes _stdint.h
dnl also, Windows does not have long long
AX_CREATE_STDINT_H
gst-libs/gst/riff/Makefile
gst-libs/gst/rtp/Makefile
gst-libs/gst/tag/Makefile
+gst-libs/gst/utils/Makefile
gst-libs/gst/video/Makefile
tools/Makefile
win32/common/config.h
<!ENTITY GstTag SYSTEM "xml/gsttag.xml">
<!ENTITY GstTagVorbis SYSTEM "xml/gsttagvorbis.xml">
<!ENTITY GstTagID3 SYSTEM "xml/gsttagid3.xml">
+<!-- utils -->
+<!ENTITY GstBaseUtils SYSTEM "xml/gstbaseutils.xml">
+<!ENTITY GstBaseUtilsDescriptions SYSTEM "xml/gstbaseutilsdescriptions.xml">
+<!ENTITY GstBaseUtilsMissingPlugins SYSTEM "xml/gstbaseutilsmissingplugins.xml">
<!-- video -->
<!ENTITY GstVideo SYSTEM "xml/gstvideo.xml">
<!ENTITY GstVideoFilter SYSTEM "xml/gstvideofilter.xml">
&GstTagID3;
</chapter>
+ <chapter id="gstreamer-base-utils">
+ <title>Base Utils Library</title>
+ <para>
+ This library should be linked to by getting cflags and libs from
+ <filename>gstreamer-plugins-base.pc</filename> and adding
+ <filename>-lgstbaseutils-&GST_MAJORMINOR;</filename> to the library
+ flags.
+ </para>
+ &GstBaseUtils;
+ &GstBaseUtilsDescriptions;
+ &GstBaseUtilsMissingPlugins;
+ </chapter>
+
<chapter id="gstreamer-video">
<title>Video Library</title>
<para>
gst_tag_to_id3_tag
</SECTION>
+# base utils
+
+<SECTION>
+<FILE>gstbaseutils</FILE>
+<INCLUDE>gst/utils/base-utils.h</INCLUDE>
+<SUBSECTION>
+gst_base_utils_init
+</SECTION>
+
+<SECTION>
+<FILE>gstbaseutilsmissingplugins</FILE>
+<INCLUDE>gst/utils/missing-plugins.h</INCLUDE>
+<SUBSECTION>
+gst_missing_plugin_message_get_installer_detail
+gst_missing_plugin_message_get_description
+gst_is_missing_plugin_message
+<SUBSECTION>
+gst_missing_decoder_message_new
+gst_missing_encoder_message_new
+gst_missing_uri_source_message_new
+gst_missing_uri_sink_message_new
+gst_missing_element_message_new
+</SECTION>
+
+<SECTION>
+<FILE>gstbaseutilsdescriptions</FILE>
+<INCLUDE>gst/utils/descriptions.h</INCLUDE>
+<SUBSECTION>
+gst_base_utils_get_source_description
+gst_base_utils_get_sink_description
+gst_base_utils_get_decoder_description
+gst_base_utils_get_encoder_description
+gst_base_utils_get_element_description
+<SUBSECTION>
+gst_base_utils_add_codec_description_to_tag_list
+gst_base_utils_get_codec_description
+</SECTION>
# video
netbuffer \
riff \
rtp \
+ utils \
video
noinst_HEADERS = gettext.h gst-i18n-plugin.h
--- /dev/null
+lib_LTLIBRARIES = libgstbaseutils-@GST_MAJORMINOR@.la
+
+libgstbaseutils_@GST_MAJORMINOR@_la_SOURCES = \
+ base-utils.c \
+ base-utils.h \
+ descriptions.c \
+ descriptions.h \
+ missing-plugins.c \
+ missing-plugins.h
+
+libgstbaseutils_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/utils
+libgstbaseutils_@GST_MAJORMINOR@include_HEADERS = \
+ base-utils.h \
+ descriptions.h \
+ missing-plugins.h
+
+libgstbaseutils_@GST_MAJORMINOR@_la_LIBADD = $(GST_LIBS)
+libgstbaseutils_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstbaseutils_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
--- /dev/null
+/* GStreamer base utils library source/sink/codec description support
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gst/gst-i18n-plugin.h"
+
+#include "base-utils.h"
+
+#include <string.h>
+
+typedef enum
+{
+ FLAG_CONTAINER = (1 << 0), /* format is a container format (muxed) */
+ FLAG_SYSTEMSTREAM = (1 << 1) /* match record only if caps have systemstream=true */
+} FormatFlags;
+
+typedef struct
+{
+ const gchar *type;
+ const gchar *desc;
+ FormatFlags flags;
+} FormatInfo;
+
+static const FormatInfo formats[] = {
+ /* container formats with static descriptions */
+ {"application/ogg", "Ogg", FLAG_CONTAINER},
+ {"application/vnd.rn-realmedia", "Realmedia", FLAG_CONTAINER},
+ {"video/x-fli", "FLI/FLC/FLX Animation", FLAG_CONTAINER},
+ {"video/x-flv", "Flash", FLAG_CONTAINER},
+ {"video/x-matroska", "Matroska", FLAG_CONTAINER},
+ {"video/x-ms-asf", "Advanced Streaming Format (ASF)", FLAG_CONTAINER},
+ {"video/x-msvideo", "AVI", FLAG_CONTAINER},
+ {"video/x-quicktime", "Quicktime", FLAG_CONTAINER},
+ {"video/quicktime", "Quicktime", FLAG_CONTAINER},
+
+ /* audio formats with static descriptions */
+ {"audio/x-ac3", "AC-3 (ATSC A/52)", 0},
+ {"audio/ac3", "AC-3 (ATSC A/52)", 0},
+ {"audio/x-private-ac3", "DVD AC-3 (ATSC A/52)", 0},
+ {"audio/x-private1-ac3", "DVD AC-3 (ATSC A/52)", 0},
+ {"audio/x-adpcm", "ADPCM", 0},
+ {"audio/aiff", "Audio Interchange File Format (AIFF)", 0},
+ {"audio/x-alaw", "A-Law", 0},
+ {"audio/amr", "Adaptive Multi Rate (AMR)", 0},
+ {"audio/AMR", "Adaptive Multi Rate (AMR)", 0},
+ {"audio/AMR-WB", "Adaptive Multi Rate WideBand (AMR-WB)", 0},
+ {"audio/iLBC-sh", "Internet Low Bitrate Codec (iLBC)", 0},
+ {"audio/ms-gsm", "MS GSM", 0},
+ {"audio/qcelp", "QCELP", 0},
+ {"audio/x-adpcm", "ADPCM", 0}, /* TODO: different variants */
+ {"audio/x-aiff", "Audio Interchange File Format (AIFF)", 0},
+ {"audio/x-alac", N_("Apple Lossless Audio (ALAC)"), 0},
+ {"audio/x-amr-nb-sh", "Adaptive Multi Rate NarrowBand (AMR-NB)", 0},
+ {"audio/x-amr-wb-sh", "Adaptive Multi Rate WideBand (AMR-WB)", 0},
+ {"audio/x-au", "Sun .au", 0},
+ {"audio/x-cinepak", "Cinepak Audio", 0},
+ {"audio/x-dpcm", "DPCM", 0},
+ {"audio/x-dts", "DTS", 0},
+ {"audio/x-dv", "DV Audio", 0},
+ {"audio/x-flac", N_("Free Lossless Audio Codec (FLAC)"), 0},
+ {"audio/x-gsm", "GSM", 0},
+ {"audio/x-iec958", "S/PDIF IEC958", 0}, /* TODO: check description */
+ {"audio/x-iLBC", "Internet Low Bitrate Codec (iLBC)", 0},
+ {"audio/x-ircam", "Berkeley/IRCAM/CARL", 0},
+ {"audio/x-lpcm", "LPCM", 0},
+ {"audio/x-private1-lpcm", "DVD LPCM", 0},
+ {"audio/x-m4a", "MPEG-4 AAC", FLAG_CONTAINER},
+ {"audio/x-mod", "Module Music Format (MOD)", 0},
+ {"audio/x-mulaw", "Mu-Law", 0},
+ {"audio/x-musepack", "Musepack (MPC)", 0},
+ {"audio/x-nist", "Sphere NIST", 0},
+ {"audio/x-nsf", "Nintendo NSF", 0},
+ {"audio/x-paris", "Ensoniq PARIS", 0},
+ {"audio/x-qdm2", "QDesign Music (QDM) 2", 0},
+ {"audio/x-ralf-mpeg4-generic", "Real Audio Lossless (RALF)", 0},
+ {"audio/x-sds", "SDS", 0},
+ {"audio/x-shorten", "Shorten Lossless", 0},
+ {"audio/x-sid", "Sid", 0},
+ {"audio/x-sipro", "Sipro/ACELP.NET Voice", 0},
+ {"audio/x-spc", "SNES-SPC700 Sound File Data", 0},
+ {"audio/x-speex", "Speex", 0},
+ {"audio/x-svx", "Amiga IFF / SVX8 / SV16", 0},
+ {"audio/x-tta", N_("Lossless True Audio (TTA)"), 0},
+ {"audio/x-ttafile", N_("Lossless True Audio (TTA)"), 0},
+ {"audio/x-vnd.sony.atrac3", "Sony ATRAC3", 0},
+ {"audio/x-vorbis", "Vorbis", 0},
+ {"audio/x-voc", "SoundBlaster VOC", 0},
+ {"audio/x-w64", "Sonic Foundry Wave64", 0},
+ {"audio/x-wav", "WAV", 0},
+ {"audio/x-wavpack", "Wavpack", 0},
+ {"audio/x-wavpack-correction", "Wavpack", 0},
+ {"audio/x-wms", N_("Windows Media Speech"), 0},
+ {"audio/x-voxware", "Voxware", 0},
+
+
+ /* video formats with static descriptions */
+ {"video/sp5x", "Sunplus JPEG 5.x", 0},
+ {"video/vivo", "Vivo", 0},
+ {"video/x-3ivx", "3ivx", 0},
+ {"video/x-4xm", "4X Techologies Video", 0},
+ {"video/x-apple-video", "Apple video", 0},
+ {"video/x-camtasia", "TechSmith Camtasia", 0},
+ {"video/x-cdxa", "RIFF/CDXA (VCD)", 0},
+ {"video/x-cinepak", "Cinepak Video", 0},
+ {"video/x-cirrus-logic-accupak", "Cirrus Logipak AccuPak", 0},
+ {"video/x-compressed-yuv", N_("CYUV Lossless"), 0},
+ {"video/x-dirac", "Dirac", 0},
+ {"video/x-dvd-subpicture", "DVD subpicture", 0},
+ {"video/x-ffv", N_("FFMpeg v1"), 0},
+ {"video/x-flash-screen", "Flash Screen Video", 0},
+ {"video/x-flash-video", "Flash Video", 0},
+ {"video/x-h261", "H.261", 0},
+ {"video/x-huffyuv", "Huffyuv", 0},
+ {"video/x-intel-h263", "Intel H.263", 0},
+ {"video/x-jpeg", "Motion JPEG", 0},
+ /* { "video/x-jpeg-b", "", 0 }, does this actually exist? */
+ {"video/x-mjpeg", "Motion-JPEG", 0},
+ {"video/x-mjpeg-b", "Motion-JPEG format B", 0},
+ {"video/mpegts", "MPEG-2 Transport Stream", FLAG_CONTAINER},
+ {"video/x-mng", "Multiple Image Network Graphics (MNG)", 0},
+ {"video/x-mszh", N_("Lossless MSZH"), 0},
+ {"video/x-msvideocodec", "Microsoft Video 1", 0},
+ {"video/x-mve", "Interplay MVE", FLAG_CONTAINER},
+ {"video/x-nut", "NUT", FLAG_CONTAINER},
+ {"video/x-nuv", "MythTV NuppelVideo (NUV)", FLAG_CONTAINER},
+ {"video/x-qdrw", "Apple QuickDraw", 0},
+ {"video/x-raw-gray", N_("Uncompressed Gray Image"), 0},
+ {"video/x-smc", "Apple SMC", 0},
+ {"video/x-smoke", "Smoke", 0},
+ {"video/x-tarkin", "Tarkin", 0},
+ {"video/x-theora", "Theora", 0},
+ {"video/x-rle", N_("Run-length encoding"), 0},
+ {"video/x-ultimotion", "IBM UltiMotion", 0},
+ {"video/x-vcd", "VideoCD (VCD)", 0},
+ {"video/x-vmnc", "VMWare NC", 0},
+ {"video/x-vp3", "On2 VP3", 0},
+ {"video/x-vp5", "On2 VP5", 0},
+ {"video/x-vp6", "On2 VP6", 0},
+ {"video/x-vp6-flash", "On2 VP6/Flash", 0},
+ {"video/x-vp7", "On2 VP7", 0},
+ {"video/x-xvid", "XVID MPEG-4", 0},
+ {"video/x-zlib", "Lossless zlib video", 0},
+
+ /* image formats with static descriptions */
+ {"image/bmp", "BMP", 0},
+ {"image/x-bmp", "BMP", 0},
+ {"image/x-MS-bmp", "BMP", 0},
+ {"image/gif", "GIF", 0},
+ {"image/jpeg", "JPEG", 0},
+ {"image/jng", "JPEG Network Graphics (JNG)", 0},
+ {"image/png", "PNG", 0},
+ {"image/pbm", "PBM", 0},
+ {"image/ppm", "PPM", 0},
+ {"image/svg+xml", "Scalable Vector Graphics (SVG)", 0},
+ {"image/tiff", "TIFF", 0},
+ {"image/x-cmu-raster", "CMU Raster Format", 0},
+ {"image/x-icon", "ICO", 0},
+ {"image/x-xcf", "XFC", 0},
+ {"image/x-pixmap", "XPM", 0},
+ {"image/x-xpixmap", "XPM", 0},
+ {"image/x-quicktime", "QuickTime Image Format (QTIF)", 0},
+ {"image/x-sun-raster", "Sun Raster Format (RAS)", 0},
+ {"image/x-tga", "TGA", 0},
+
+ /* formats with dynamic descriptions */
+ {"audio/mpeg", NULL, 0},
+ {"audio/x-mace", NULL, 0},
+ {"audio/x-pn-realaudio", NULL, 0},
+ {"audio/x-raw-int", NULL, 0},
+ {"audio/x-raw-float", NULL, 0},
+ {"audio/x-wma", NULL, 0},
+ {"video/mpeg", NULL, FLAG_CONTAINER | FLAG_SYSTEMSTREAM},
+ {"video/mpeg", NULL, 0},
+ {"video/x-asus", NULL, 0},
+ {"video/x-ati-vcr", NULL, 0},
+ {"video/x-divx", NULL, 0},
+ {"video/x-dv", "Digital Video (DV) System Stream",
+ FLAG_CONTAINER | FLAG_SYSTEMSTREAM},
+ {"video/x-dv", "Digital Video (DV)", 0},
+ {"video/x-h263", NULL, 0},
+ {"video/x-h264", NULL, 0},
+ {"video/x-indeo", NULL, 0},
+ {"video/x-msmpeg", NULL, 0},
+ {"video/x-pn-realvideo", NULL, 0},
+#if 0
+ /* do these exist? are they used anywhere? */
+ {"video/x-pn-multirate-realvideo", NULL, 0},
+ {"audio/x-pn-multirate-realaudio", NULL, 0},
+ {"audio/x-pn-multirate-realaudio-live", NULL, 0},
+#endif
+ {"video/x-truemotion", NULL, 0},
+ {"video/x-raw-rgb", NULL, 0},
+ {"video/x-raw-yuv", NULL, 0},
+ {"video/x-svq", NULL, 0},
+ {"video/x-wmv", NULL, 0},
+ {"video/x-xan", NULL, 0}
+};
+
+/* returns static descriptions and dynamic ones (such as video/x-raw-yuv),
+ * or NULL if caps aren't known at all */
+static gchar *
+format_info_get_desc (const FormatInfo * info, const GstCaps * caps)
+{
+ const GstStructure *s;
+
+ g_assert (info != NULL);
+
+ if (info->desc != NULL)
+ return g_strdup (_(info->desc));
+
+ s = gst_caps_get_structure (caps, 0);
+
+ if (strcmp (info->type, "video/x-raw-yuv") == 0) {
+ const gchar *ret = NULL;
+ guint32 fourcc = 0;
+
+ gst_structure_get_fourcc (s, "format", &fourcc);
+ switch (fourcc) {
+ case GST_MAKE_FOURCC ('I', '4', '2', '0'):
+ ret = _("Uncompressed planar YUV 4:2:0");
+ break;
+ case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
+ ret = _("Uncompressed planar YVU 4:2:0");
+ break;
+ case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
+ ret = _("Uncompressed packed YUV 4:2:2");
+ break;
+ case GST_MAKE_FOURCC ('Y', 'U', 'V', '9'):
+ ret = _("Uncompressed packed YUV 4:1:0");
+ break;
+ case GST_MAKE_FOURCC ('Y', 'V', 'U', '9'):
+ ret = _("Uncompressed packed YVU 4:1:0");
+ break;
+ case GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U'):
+ case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
+ ret = _("Uncompressed packed YUV 4:2:2");
+ break;
+ case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
+ ret = _("Uncompressed packed YUV 4:1:1");
+ break;
+ case GST_MAKE_FOURCC ('I', 'Y', 'U', '2'):
+ ret = _("Uncompressed packed YUV 4:4:4");
+ break;
+ case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
+ ret = _("Uncompressed planar YUV 4:2:2");
+ break;
+ case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
+ ret = _("Uncompressed planar YUV 4:1:1");
+ break;
+ case GST_MAKE_FOURCC ('Y', '8', '0', '0'):
+ ret = _("Uncompressed black and white Y-plane");
+ break;
+ default:
+ ret = _("Uncompressed YUV");
+ break;
+ }
+ return g_strdup (ret);
+ } else if (strcmp (info->type, "video/x-raw-rgb") == 0) {
+ const gchar *rgb_str;
+ gint depth = 0;
+
+ gst_structure_get_int (s, "depth", &depth);
+ rgb_str = gst_structure_has_field (s, "alpha_mask") ? "RGBA" : "RGB";
+ if (gst_structure_has_field (s, "paletted_data")) {
+ return g_strdup_printf (_("Uncompressed palettized %d-bit %s"), depth,
+ rgb_str);
+ } else {
+ return g_strdup_printf ("Uncompressed %d-bit %s", depth, rgb_str);
+ }
+ } else if (strcmp (info->type, "video/x-h263") == 0) {
+ const gchar *variant, *ret;
+
+ variant = gst_structure_get_string (s, "variant");
+ if (variant == NULL)
+ ret = "H.263";
+ else if (strcmp (variant, "itu") == 0)
+ ret = "ITU H.26n"; /* why not ITU H.263? (tpm) */
+ else if (strcmp (variant, "lead") == 0)
+ ret = "Lead H.263";
+ else if (strcmp (variant, "microsoft") == 0)
+ ret = "Microsoft H.263";
+ else if (strcmp (variant, "vdolive") == 0)
+ ret = "VDOLive";
+ else if (strcmp (variant, "vivo") == 0)
+ ret = "Vivo H.263";
+ else if (strcmp (variant, "xirlink") == 0)
+ ret = "Xirlink H.263";
+ else {
+ GST_WARNING ("Unknown H263 variant '%s'", variant);
+ ret = "H.263";
+ }
+ return g_strdup (ret);
+ } else if (strcmp (info->type, "video/x-h264") == 0) {
+ const gchar *variant, *ret;
+
+ variant = gst_structure_get_string (s, "variant");
+ if (variant == NULL)
+ ret = "H.264";
+ else if (strcmp (variant, "itu") == 0)
+ ret = "ITU H.264";
+ else if (strcmp (variant, "videosoft") == 0)
+ ret = "Videosoft H.264";
+ else {
+ GST_WARNING ("Unknown H264 variant '%s'", variant);
+ ret = "H.264";
+ }
+ return g_strdup (ret);
+ } else if (strcmp (info->type, "video/x-divx") == 0) {
+ gint ver = 0;
+
+ if (!gst_structure_get_int (s, "divxversion", &ver) || ver <= 2) {
+ GST_WARNING ("Unexpected DivX version in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("DivX MPEG-4");
+ }
+ return g_strdup_printf (_("DivX MPEG-4 Version %d"), ver);
+ } else if (strcmp (info->type, "video/x-msmpeg") == 0) {
+ gint ver = 0;
+
+ if (!gst_structure_get_int (s, "msmpegversion", &ver) ||
+ ver < 40 || ver > 49) {
+ GST_WARNING ("Unexpected msmpegversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Microsoft MPEG-4 4.x");
+ }
+ return g_strdup_printf ("Microsoft MPEG-4 4.%d", ver % 10);
+ } else if (strcmp (info->type, "video/x-truemotion") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "trueversion", &ver);
+ switch (ver) {
+ case 1:
+ return g_strdup_printf ("Duck TrueMotion 1");
+ case 2:
+ return g_strdup_printf ("TrueMotion 2.0");
+ default:
+ GST_WARNING ("Unexpected trueversion in %" GST_PTR_FORMAT, caps);
+ break;
+ }
+ return g_strdup_printf ("TrueMotion");
+ } else if (strcmp (info->type, "video/x-xan") == 0) {
+ gint ver = 0;
+
+ if (!gst_structure_get_int (s, "wcversion", &ver) || ver < 1) {
+ GST_WARNING ("Unexpected wcversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Xan Wing Commander");
+ }
+ return g_strdup_printf ("Xan Wing Commander %u", ver);
+ } else if (strcmp (info->type, "video/x-indeo") == 0) {
+ gint ver = 0;
+
+ if (!gst_structure_get_int (s, "indeoversion", &ver) || ver < 2) {
+ GST_WARNING ("Unexpected indeoversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Intel Indeo");
+ }
+ return g_strdup_printf ("Intel Indeo %u", ver);
+ } else if (strcmp (info->type, "audio/x-wma") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "wmaversion", &ver);
+ switch (ver) {
+ case 1:
+ case 2:
+ case 3:
+ return g_strdup_printf ("Windows Media Audio %d", ver + 6);
+ default:
+ break;
+ }
+ GST_WARNING ("Unexpected wmaversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Windows Media Audio");
+ } else if (strcmp (info->type, "video/x-wmv") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "wmvversion", &ver);
+ switch (ver) {
+ case 1:
+ case 2:
+ case 3:
+ return g_strdup_printf ("Windows Media Video %d", ver + 6);
+ default:
+ break;
+ }
+ GST_WARNING ("Unexpected wmvversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Windows Media Video");
+ } else if (strcmp (info->type, "audio/x-mace") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "maceversion", &ver);
+ if (ver == 3 || ver == 6) {
+ return g_strdup_printf ("MACE-%d", ver);
+ } else {
+ GST_WARNING ("Unexpected maceversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("MACE");
+ }
+ } else if (strcmp (info->type, "video/x-svq") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "svqversion", &ver);
+ if (ver == 1 || ver == 3) {
+ return g_strdup_printf ("Sorensen Video %d", ver);
+ } else {
+ GST_WARNING ("Unexpected svqversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Sorensen Video");
+ }
+ } else if (strcmp (info->type, "video/x-asus") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "asusversion", &ver);
+ if (ver == 1 || ver == 2) {
+ return g_strdup_printf ("Asus Video %d", ver);
+ } else {
+ GST_WARNING ("Unexpected asusversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Asus Video");
+ }
+ } else if (strcmp (info->type, "video/x-ati-vcr") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "vcrversion", &ver);
+ if (ver == 1 || ver == 2) {
+ return g_strdup_printf ("ATI VCR %d", ver);
+ } else {
+ GST_WARNING ("Unexpected acrversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("ATI VCR");
+ }
+ } else if (strcmp (info->type, "audio/mpeg") == 0) {
+ gint ver = 0, layer = 0;
+
+ gst_structure_get_int (s, "mpegversion", &ver);
+
+ switch (ver) {
+ case 1:
+ gst_structure_get_int (s, "layer", &layer);
+ switch (layer) {
+ case 1:
+ case 2:
+ case 3:
+ return g_strdup_printf ("MPEG-1 Layer %d (MP%d)", layer, layer);
+ default:
+ break;
+ }
+ GST_WARNING ("Unexpected MPEG-1 layer in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("MPEG-1 Audio");
+ case 4:
+ return g_strdup ("MPEG-4 AAC");
+ default:
+ break;
+ }
+ GST_WARNING ("Unexpected audio mpegversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("MPEG Audio");
+ } else if (strcmp (info->type, "audio/x-pn-realaudio") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "raversion", &ver);
+ switch (ver) {
+ case 1:
+ return g_strdup ("RealAudio 14k4bps");
+ case 2:
+ return g_strdup ("RealAudio 28k8bps");
+ case 8:
+ return g_strdup ("RealAudio G2 (Cook)");
+ default:
+ break;
+ }
+ GST_WARNING ("Unexpected raversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("RealAudio");
+ } else if (strcmp (info->type, "video/x-pn-realvideo") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "rmversion", &ver);
+ switch (ver) {
+ case 1:
+ return g_strdup ("RealVideo 1.0");
+ case 2:
+ return g_strdup ("RealVideo 2.0");
+ case 3:
+ return g_strdup ("RealVideo 3.0");
+ case 4:
+ return g_strdup ("RealVideo 4.0");
+ default:
+ break;
+ }
+ GST_WARNING ("Unexpected rmversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("RealVideo");
+ } else if (strcmp (info->type, "video/mpeg") == 0) {
+ gboolean sysstream;
+ gint ver = 0;
+
+ if (!gst_structure_get_boolean (s, "systemstream", &sysstream) ||
+ !gst_structure_get_int (s, "mpegversion", &ver) || ver < 1 || ver > 4) {
+ GST_WARNING ("Missing fields in mpeg video caps %" GST_PTR_FORMAT, caps);
+ } else {
+ if (sysstream) {
+ return g_strdup_printf ("MPEG-%d System Stream", ver);
+ } else {
+ return g_strdup_printf ("MPEG-%d Video", ver);
+ }
+ }
+ return g_strdup ("MPEG Video");
+ } else if (strcmp (info->type, "audio/x-raw-int") == 0) {
+ gint bitdepth = 0;
+
+ /* 8-bit pcm might not have depth field (?) */
+ if (!gst_structure_get_int (s, "depth", &bitdepth))
+ gst_structure_get_int (s, "width", &bitdepth);
+ if (bitdepth != 0)
+ return g_strdup_printf (_("Raw %d-bit PCM audio"), bitdepth);
+ else
+ return g_strdup (_("Raw PCM audio"));
+ } else if (strcmp (info->type, "audio/x-raw-float") == 0) {
+ gint bitdepth = 0;
+
+ gst_structure_get_int (s, "width", &bitdepth);
+ if (bitdepth != 0)
+ return g_strdup_printf (_("Raw %d-bit floating-point audio"), bitdepth);
+ else
+ return g_strdup (_("Raw floating-point audio"));
+ }
+
+ return NULL;
+}
+
+/* returns format info structure, will return NULL for dynamic media types! */
+static const FormatInfo *
+find_format_info (const GstCaps * caps)
+{
+ const GstStructure *s;
+ const gchar *media_type;
+ guint i;
+
+ s = gst_caps_get_structure (caps, 0);
+ media_type = gst_structure_get_name (s);
+
+ for (i = 0; i < G_N_ELEMENTS (formats); ++i) {
+ if (strcmp (media_type, formats[i].type) == 0) {
+ gboolean is_sys = FALSE;
+
+ if ((formats[i].flags & FLAG_SYSTEMSTREAM) == 0)
+ return &formats[i];
+
+ /* this record should only be matched if the systemstream field is set */
+ if (gst_structure_get_boolean (s, "systemstream", &is_sys) && is_sys)
+ return &formats[i];
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean
+caps_are_rtp_caps (const GstCaps * caps, const gchar * media, gchar ** format)
+{
+ const GstStructure *s;
+ const gchar *str;
+
+ g_assert (media != NULL && format != NULL);
+
+ s = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_has_name (s, "application/x-rtp"))
+ return FALSE;
+ if (!gst_structure_has_field_typed (s, "media", G_TYPE_STRING))
+ return FALSE;
+ str = gst_structure_get_string (s, "media");
+ if (str == NULL || !g_str_equal (str, media))
+ return FALSE;
+ str = gst_structure_get_string (s, "encoding-name");
+ if (str == NULL || *str == '\0')
+ return FALSE;
+ *format = g_strdup (str);
+ return TRUE;
+}
+
+/**
+ * gst_base_utils_get_source_description:
+ * @protocol: the protocol the source element needs to handle, e.g. "http"
+ *
+ * Returns a localised string describing a source element handling the protocol
+ * specified in @protocol, for use in error dialogs or other messages to be
+ * seen by the user. Should never return NULL unless @protocol is invalid.
+ *
+ * This function is mainly for internal use, applications would typically
+ * use gst_missing_plugin_message_get_description() to get a description of
+ * a missing feature from a missing-plugin message.
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_base_utils_get_source_description (const gchar * protocol)
+{
+ gchar *proto_uc, *ret;
+
+ g_return_val_if_fail (protocol != NULL, NULL);
+
+ if (strcmp (protocol, "cdda") == 0)
+ return g_strdup (_("Audio CD source"));
+
+ if (strcmp (protocol, "dvd") == 0)
+ return g_strdup (_("DVD source"));
+
+ if (strcmp (protocol, "rtsp") == 0)
+ return g_strdup (_("Real Time Streaming Protocol (RTSP) source"));
+
+ /* TODO: what about mmst, mmsu, mmsh? */
+ if (strcmp (protocol, "mms") == 0)
+ return g_strdup (_("Microsoft Media Server (MMS) protocol source"));
+
+ /* make protocol uppercase */
+ proto_uc = g_ascii_strup (protocol, -1);
+
+ /* TODO: find out how to add a comment for translators to the source code
+ * (and tell them to make the first letter uppercase below if they move
+ * the protocol to the middle or end of the string) */
+ ret = g_strdup_printf (_("%s protocol source"), proto_uc);
+
+ g_free (proto_uc);
+
+ return ret;
+}
+
+/**
+ * gst_base_utils_get_sink_description:
+ * @protocol: the protocol the sink element needs to handle, e.g. "http"
+ *
+ * Returns a localised string describing a sink element handling the protocol
+ * specified in @protocol, for use in error dialogs or other messages to be
+ * seen by the user. Should never return NULL unless @protocol is invalid.
+ *
+ * This function is mainly for internal use, applications would typically
+ * use gst_missing_plugin_message_get_description() to get a description of
+ * a missing feature from a missing-plugin message.
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_base_utils_get_sink_description (const gchar * protocol)
+{
+ gchar *proto_uc, *ret;
+
+ g_return_val_if_fail (protocol != NULL, NULL);
+
+ /* make protocol uppercase */
+ proto_uc = g_ascii_strup (protocol, -1);
+
+ /* TODO: find out how to add a comment for translators to the source code
+ * (and tell them to make the first letter uppercase below if they move
+ * the protocol to the middle or end of the string) */
+ ret = g_strdup_printf ("%s protocol sink", proto_uc);
+
+ g_free (proto_uc);
+
+ return ret;
+}
+
+/**
+ * gst_base_utils_get_decoder_description:
+ * @caps: the (fixed) #GstCaps for which an decoder description is needed
+ *
+ * Returns a localised string describing an decoder for the format specified
+ * in @caps, for use in error dialogs or other messages to be seen by the user.
+ * Should never return NULL unless @factory_name or @caps are invalid.
+ *
+ * This function is mainly for internal use, applications would typically
+ * use gst_missing_plugin_message_get_description() to get a description of
+ * a missing feature from a missing-plugin message.
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_base_utils_get_decoder_description (const GstCaps * caps)
+{
+ gchar *str, *ret;
+
+ g_return_val_if_fail (caps != NULL, NULL);
+ g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
+ g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
+
+ /* special-case RTP caps */
+ if (caps_are_rtp_caps (caps, "video", &str)) {
+ ret = g_strdup_printf (_("%s video RTP depayloader"), str);
+ } else if (caps_are_rtp_caps (caps, "audio", &str)) {
+ ret = g_strdup_printf (_("%s audio RTP depayloader"), str);
+ } else if (caps_are_rtp_caps (caps, "application", &str)) {
+ ret = g_strdup_printf (_("%s RTP depayloader"), str);
+ } else {
+ const FormatInfo *info;
+
+ str = gst_base_utils_get_codec_description (caps);
+ info = find_format_info (caps);
+ if (info != NULL && (info->flags & FLAG_CONTAINER) != 0) {
+ ret = g_strdup_printf (_("%s demuxer"), str);
+ } else {
+ ret = g_strdup_printf (_("%s decoder"), str);
+ }
+ }
+
+ g_free (str);
+
+ return ret;
+}
+
+/**
+ * gst_base_utils_get_encoder_description:
+ * @caps: the (fixed) #GstCaps for which an encoder description is needed
+ *
+ * Returns a localised string describing an encoder for the format specified
+ * in @caps, for use in error dialogs or other messages to be seen by the user.
+ * Should never return NULL unless @factory_name or @caps are invalid.
+ *
+ * This function is mainly for internal use, applications would typically
+ * use gst_missing_plugin_message_get_description() to get a description of
+ * a missing feature from a missing-plugin message.
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_base_utils_get_encoder_description (const GstCaps * caps)
+{
+ gchar *str, *ret;
+
+ g_return_val_if_fail (caps != NULL, NULL);
+ g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
+ g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
+
+ /* special-case RTP caps */
+ if (caps_are_rtp_caps (caps, "video", &str)) {
+ ret = g_strdup_printf (_("%s video RTP payloader"), str);
+ } else if (caps_are_rtp_caps (caps, "audio", &str)) {
+ ret = g_strdup_printf (_("%s audio RTP payloader"), str);
+ } else if (caps_are_rtp_caps (caps, "application", &str)) {
+ ret = g_strdup_printf (_("%s RTP payloader"), str);
+ } else {
+ const FormatInfo *info;
+
+ str = gst_base_utils_get_codec_description (caps);
+ info = find_format_info (caps);
+ if (info != NULL && (info->flags & FLAG_CONTAINER) != 0) {
+ ret = g_strdup_printf (_("%s muxer"), str);
+ } else {
+ ret = g_strdup_printf (_("%s encoder"), str);
+ }
+ }
+
+ g_free (str);
+
+ return ret;
+}
+
+/**
+ * gst_base_utils_get_element_description:
+ * @factory_name: the name of the element, e.g. "gnomevfssrc"
+ *
+ * Returns a localised string describing the given element, for use in
+ * error dialogs or other messages to be seen by the user. Should never
+ * return NULL unless @factory_name is invalid.
+ *
+ * This function is mainly for internal use, applications would typically
+ * use gst_missing_plugin_message_get_description() to get a description of
+ * a missing feature from a missing-plugin message.
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_base_utils_get_element_description (const gchar * factory_name)
+{
+ gchar *ret;
+
+ g_return_val_if_fail (factory_name != NULL, NULL);
+
+ ret = g_strdup_printf (_("GStreamer element %s"), factory_name);
+ if (ret && g_str_has_prefix (ret, factory_name))
+ *ret = g_ascii_toupper (*ret);
+
+ return ret;
+}
+
+/**
+ * gst_base_utils_add_codec_description_to_tag_list:
+ * @taglist: a #GstTagList
+ * @codec_tag: a GStreamer codec tag such as #GST_TAG_AUDIO_CODEC,
+ * #GST_TAG_VIDEO_CODEC or #GST_TAG_CODEC
+ * @caps: the (fixed) #GstCaps for which a codec tag should be added.
+ *
+ * Adds a codec tag describing the format specified by @caps to @taglist.
+ *
+ * Returns: TRUE if a codec tag was added, FALSE otherwise.
+ */
+gboolean
+gst_base_utils_add_codec_description_to_tag_list (GstTagList * taglist,
+ const gchar * codec_tag, const GstCaps * caps)
+{
+ const FormatInfo *info;
+ gchar *desc;
+
+ g_return_val_if_fail (taglist != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_TAG_LIST (taglist), FALSE);
+ g_return_val_if_fail (codec_tag != NULL, FALSE);
+ g_return_val_if_fail (gst_tag_exists (codec_tag), FALSE);
+ g_return_val_if_fail (gst_tag_get_type (codec_tag) == G_TYPE_STRING, FALSE);
+ g_return_val_if_fail (caps != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
+
+ info = find_format_info (caps);
+ if (info == NULL)
+ return FALSE;
+
+ desc = format_info_get_desc (info, caps);
+ gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, codec_tag, desc, NULL);
+ g_free (desc);
+
+ return TRUE;
+}
+
+/**
+ * gst_base_utils_get_codec_description:
+ * @caps: the (fixed) #GstCaps for which an format description is needed
+ *
+ * Returns a localised (as far as this is possible) string describing the
+ * media format specified in @caps, for use in error dialogs or other messages
+ * to be seen by the user. Should never return NULL unless @caps is invalid.
+ *
+ * Also see the convenience function
+ * gst_base_utils_add_codec_description_to_tag_list().
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_base_utils_get_codec_description (const GstCaps * caps)
+{
+ const FormatInfo *info;
+ gchar *str, *comma;
+
+ g_return_val_if_fail (caps != NULL, NULL);
+ g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
+ g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
+
+ info = find_format_info (caps);
+
+ if (info) {
+ str = format_info_get_desc (info, caps);
+ } else {
+ str = gst_caps_to_string (caps);
+
+ /* cut off everything after the media type, if there is anything */
+ if ((comma = strchr (str, ','))) {
+ *comma = '\0';
+ g_strchomp (str);
+ /* we could do something more elaborate here, like taking into account
+ * audio/, video/, image/ and application/ prefixes etc. */
+ }
+
+ GST_WARNING ("No description available for media type: %s", str);
+ }
+
+ return str;
+}
+
+#if 0
+void
+gst_base_utils_list_all (void)
+{
+ gint i;
+
+ g_print ("static const gchar *caps_strings[] = { ");
+
+ for (i = 0; i < G_N_ELEMENTS (formats); ++i) {
+ if (formats[i].desc != NULL)
+ g_print (" \"%s\", ", formats[i].type);
+ }
+ g_print ("\n#if 0\n");
+ for (i = 0; i < G_N_ELEMENTS (formats); ++i) {
+ if (formats[i].desc == NULL)
+ g_print (" \"%s\", \n", formats[i].type);
+ }
+ g_print ("\n#endif\n");
+}
+#endif
--- /dev/null
+/* GStreamer base utils library source/sink/codec description support
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_BASE_UTILS_DESCRIPTIONS_H__
+#define __GST_BASE_UTILS_DESCRIPTIONS_H__
+
+#include <gst/gsttaglist.h>
+#include <gst/gstcaps.h>
+
+G_BEGIN_DECLS
+
+/*
+ * functions for use by demuxers or decoders to add CODEC tags to tag lists
+ * from caps
+ */
+
+gboolean gst_base_utils_add_codec_description_to_tag_list (GstTagList * taglist,
+ const gchar * codec_tag,
+ const GstCaps * caps);
+
+gchar * gst_base_utils_get_codec_description (const GstCaps * caps);
+
+/*
+ * functions mainly used by the missing plugins message creation functions to
+ * find descriptions of what exactly is missing
+ */
+
+gchar * gst_base_utils_get_source_description (const gchar * protocol);
+
+gchar * gst_base_utils_get_sink_description (const gchar * protocol);
+
+gchar * gst_base_utils_get_decoder_description (const GstCaps * caps);
+
+gchar * gst_base_utils_get_encoder_description (const GstCaps * caps);
+
+gchar * gst_base_utils_get_element_description (const gchar * factory_name);
+
+
+G_END_DECLS
+
+#endif /* __GST_BASE_UTILS_DESCRIPTIONS_H__ */
+
--- /dev/null
+/* GStreamer base utils library missing plugins support
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> /* getpid on UNIX */
+#endif
+#ifdef HAVE_PROCESS_H
+# include <process.h> /* getpid on win32 */
+#endif
+
+#include "gst/gst-i18n-plugin.h"
+
+#include "base-utils.h"
+
+#include <string.h>
+
+#define GST_DETAIL_STRING_MARKER "gstreamer.net"
+
+typedef enum
+{
+ GST_MISSING_TYPE_UNKNOWN = 0,
+ GST_MISSING_TYPE_URISOURCE,
+ GST_MISSING_TYPE_URISINK,
+ GST_MISSING_TYPE_ELEMENT,
+ GST_MISSING_TYPE_DECODER,
+ GST_MISSING_TYPE_ENCODER
+} GstMissingType;
+
+static const struct
+{
+ GstMissingType type;
+ const gchar type_string[12];
+} missing_type_mapping[] = {
+ {
+ GST_MISSING_TYPE_URISOURCE, "urisource"}, {
+ GST_MISSING_TYPE_URISINK, "urisink"}, {
+ GST_MISSING_TYPE_ELEMENT, "element"}, {
+ GST_MISSING_TYPE_DECODER, "decoder"}, {
+ GST_MISSING_TYPE_ENCODER, "encoder"}
+};
+
+static GstMissingType
+missing_structure_get_type (const GstStructure * s)
+{
+ const gchar *type;
+ guint i;
+
+ type = gst_structure_get_string (s, "type");
+ g_return_val_if_fail (type != NULL, GST_MISSING_TYPE_UNKNOWN);
+
+ for (i = 0; i < G_N_ELEMENTS (missing_type_mapping); ++i) {
+ if (strcmp (missing_type_mapping[i].type_string, type) == 0)
+ return missing_type_mapping[i].type;
+ }
+
+ return GST_MISSING_TYPE_UNKNOWN;
+}
+
+static GstCaps *
+copy_and_clean_caps (const GstCaps * caps)
+{
+ GstStructure *s;
+ GstCaps *ret;
+
+ ret = gst_caps_copy (caps);
+
+ /* make caps easier to interpret, remove common fields that are likely
+ * to be irrelevant for determining the right plugin (ie. mostly fields
+ * where template caps usually have the standard MIN - MAX range as value) */
+ s = gst_caps_get_structure (ret, 0);
+ gst_structure_remove_field (s, "codec_data");
+ gst_structure_remove_field (s, "palette_data");
+ gst_structure_remove_field (s, "pixel-aspect-ratio");
+ gst_structure_remove_field (s, "framerate");
+ /* maybe remove width/height too? */
+
+ return ret;
+}
+
+/**
+ * gst_missing_uri_source_message_new:
+ * @element: the #GstElement posting the message
+ * @protocol: the URI protocol the missing source needs to implement,
+ * e.g. "http" or "mms"
+ *
+ * Creates a missing-plugin message for @element to notify the application
+ * that a source element for a particular URI protocol is missing. This
+ * function is mainly for use in plugins.
+ *
+ * Returns: a new #GstMessage, or NULL on error
+ */
+GstMessage *
+gst_missing_uri_source_message_new (GstElement * element,
+ const gchar * protocol)
+{
+ GstStructure *s;
+ gchar *description;
+
+ g_return_val_if_fail (element != NULL, NULL);
+ g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+ g_return_val_if_fail (protocol != NULL, NULL);
+
+ description = gst_base_utils_get_source_description (protocol);
+
+ s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
+ "urisource", "detail", G_TYPE_STRING, protocol, "name", G_TYPE_STRING,
+ description, NULL);
+
+ g_free (description);
+ return gst_message_new_element (GST_OBJECT_CAST (element), s);
+}
+
+/**
+ * gst_missing_uri_sink_message_new:
+ * @element: the #GstElement posting the message
+ * @protocol: the URI protocol the missing sink needs to implement,
+ * e.g. "http" or "smb"
+ *
+ * Creates a missing-plugin message for @element to notify the application
+ * that a sink element for a particular URI protocol is missing. This
+ * function is mainly for use in plugins.
+ *
+ * Returns: a new #GstMessage, or NULL on error
+ */
+GstMessage *
+gst_missing_uri_sink_message_new (GstElement * element, const gchar * protocol)
+{
+ GstStructure *s;
+ gchar *description;
+
+ g_return_val_if_fail (element != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+ g_return_val_if_fail (protocol != NULL, FALSE);
+
+ description = gst_base_utils_get_sink_description (protocol);
+
+ s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
+ "urisink", "detail", G_TYPE_STRING, protocol, "name", G_TYPE_STRING,
+ description, NULL);
+
+ g_free (description);
+ return gst_message_new_element (GST_OBJECT_CAST (element), s);
+}
+
+/**
+ * gst_missing_element_message_new:
+ * @element: the #GstElement posting the message
+ * @factory_name: the name of the missing element (element factory),
+ * e.g. "videoscale" or "cdparanoiasrc"
+ *
+ * Creates a missing-plugin message for @element to notify the application
+ * that a certain required element is missing. This function is mainly for
+ * use in plugins.
+ *
+ * Returns: a new #GstMessage, or NULL on error
+ */
+GstMessage *
+gst_missing_element_message_new (GstElement * element,
+ const gchar * factory_name)
+{
+ GstStructure *s;
+ gchar *description;
+
+ g_return_val_if_fail (element != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+ g_return_val_if_fail (factory_name != NULL, FALSE);
+
+ description = gst_base_utils_get_element_description (factory_name);
+
+ s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
+ "element", "detail", G_TYPE_STRING, factory_name, "name", G_TYPE_STRING,
+ description, NULL);
+
+ g_free (description);
+ return gst_message_new_element (GST_OBJECT_CAST (element), s);
+}
+
+/**
+ * gst_missing_decoder_message_new:
+ * @element: the #GstElement posting the message
+ * @decode_caps: the (fixed) caps for which a decoder element is needed
+ *
+ * Creates a missing-plugin message for @element to notify the application
+ * that a decoder element for a particular set of (fixed) caps is missing.
+ * This function is mainly for use in plugins.
+ *
+ * Returns: a new #GstMessage, or NULL on error
+ */
+GstMessage *
+gst_missing_decoder_message_new (GstElement * element,
+ const GstCaps * decode_caps)
+{
+ GstStructure *s;
+ GstCaps *caps;
+ gchar *description;
+
+ g_return_val_if_fail (element != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+ g_return_val_if_fail (decode_caps != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_CAPS (decode_caps), FALSE);
+ g_return_val_if_fail (!gst_caps_is_any (decode_caps), FALSE);
+ g_return_val_if_fail (!gst_caps_is_empty (decode_caps), FALSE);
+ g_return_val_if_fail (gst_caps_is_fixed (decode_caps), FALSE);
+
+ description = gst_base_utils_get_decoder_description (decode_caps);
+ caps = copy_and_clean_caps (decode_caps);
+
+ s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
+ "decoder", "detail", GST_TYPE_CAPS, caps, "name", G_TYPE_STRING,
+ description, NULL);
+
+ gst_caps_unref (caps);
+ g_free (description);
+
+ return gst_message_new_element (GST_OBJECT_CAST (element), s);
+}
+
+/**
+ * gst_missing_encoder_message_new:
+ * @element: the #GstElement posting the message
+ * @encode_caps: the (fixed) caps for which an encoder element is needed
+ *
+ * Creates a missing-plugin message for @element to notify the application
+ * that an encoder element for a particular set of (fixed) caps is missing.
+ * This function is mainly for use in plugins.
+ *
+ * Returns: a new #GstMessage, or NULL on error
+ */
+GstMessage *
+gst_missing_encoder_message_new (GstElement * element,
+ const GstCaps * encode_caps)
+{
+ GstStructure *s;
+ GstCaps *caps;
+ gchar *description;
+
+ g_return_val_if_fail (element != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+ g_return_val_if_fail (encode_caps != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_CAPS (encode_caps), FALSE);
+ g_return_val_if_fail (!gst_caps_is_any (encode_caps), FALSE);
+ g_return_val_if_fail (!gst_caps_is_empty (encode_caps), FALSE);
+ g_return_val_if_fail (gst_caps_is_fixed (encode_caps), FALSE);
+
+ description = gst_base_utils_get_encoder_description (encode_caps);
+ caps = copy_and_clean_caps (encode_caps);
+
+ s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
+ "encoder", "detail", GST_TYPE_CAPS, caps, "name", G_TYPE_STRING,
+ description, NULL);
+
+ gst_caps_unref (caps);
+ g_free (description);
+
+ return gst_message_new_element (GST_OBJECT_CAST (element), s);
+}
+
+static gboolean
+missing_structure_get_string_detail (const GstStructure * s, gchar ** p_detail)
+{
+ const gchar *detail;
+ GType detail_type;
+
+ *p_detail = NULL;
+
+ detail_type = gst_structure_get_field_type (s, "detail");
+ if (!g_type_is_a (detail_type, G_TYPE_STRING)) {
+ GST_WARNING ("expected 'detail' field to be of G_TYPE_STRING");
+ return FALSE;
+ }
+
+ detail = gst_structure_get_string (s, "detail");
+ if (detail == NULL || *detail == '\0') {
+ GST_WARNING ("empty 'detail' field");
+ return FALSE;
+ }
+ *p_detail = g_strdup (detail);
+ return TRUE;
+}
+
+static gboolean
+missing_structure_get_caps_detail (const GstStructure * s, GstCaps ** p_caps)
+{
+ const GstCaps *caps;
+ const GValue *val;
+ GType detail_type;
+
+ *p_caps = NULL;
+
+ detail_type = gst_structure_get_field_type (s, "detail");
+ if (!g_type_is_a (detail_type, GST_TYPE_CAPS)) {
+ GST_WARNING ("expected 'detail' field to be of GST_TYPE_CAPS");
+ return FALSE;
+ }
+
+ val = gst_structure_get_value (s, "detail");
+ caps = gst_value_get_caps (val);
+ if (gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
+ GST_WARNING ("EMPTY or ANY caps not allowed");
+ return FALSE;
+ }
+
+ *p_caps = gst_caps_copy (caps);
+ return TRUE;
+}
+
+/**
+ * gst_missing_plugin_message_get_installer_detail:
+ * @msg: a missing-plugin #GstMessage of type #GST_MESSAGE_ELEMENT
+ *
+ * Returns an opaque string containing all the details about the missing
+ * element to be passed to an external installer or installer library
+ * such as libgimme-codec.
+ *
+ * This function is mainly for applications that use libgimme-codec or
+ * other libraries that call external plugin installation mechanisms.
+ *
+ * Returns: a newly-allocated detail string, or NULL on error. Free string
+ * with g_free() when not needed any longer.
+ */
+gchar *
+gst_missing_plugin_message_get_installer_detail (GstMessage * msg)
+{
+ GstMissingType missing_type;
+ const gchar *progname;
+ const gchar *type;
+ GString *str = NULL;
+ gchar *detail = NULL;
+ gchar *desc;
+
+ g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
+
+ GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, msg->structure);
+
+ missing_type = missing_structure_get_type (msg->structure);
+ if (missing_type == GST_MISSING_TYPE_UNKNOWN) {
+ GST_WARNING ("couldn't parse 'type' field");
+ goto error;
+ }
+
+ type = gst_structure_get_string (msg->structure, "type");
+ g_assert (type != NULL); /* validity already checked above */
+
+ str = g_string_new (GST_DETAIL_STRING_MARKER "|");
+ g_string_append_printf (str, "%u.%u|", GST_VERSION_MAJOR, GST_VERSION_MINOR);
+
+ progname = (const gchar *) g_get_prgname ();
+ if (progname) {
+ g_string_append_printf (str, "%s|", progname);
+ } else {
+ g_string_append_printf (str, "pid/%lu", (gulong) getpid ());
+ }
+
+ desc = gst_missing_plugin_message_get_description (msg);
+ if (desc) {
+ g_strdelimit (desc, "|", '#');
+ g_string_append_printf (str, "%s|", desc);
+ g_free (desc);
+ } else {
+ g_string_append (str, "|");
+ }
+
+ switch (missing_type) {
+ case GST_MISSING_TYPE_URISOURCE:
+ case GST_MISSING_TYPE_URISINK:
+ case GST_MISSING_TYPE_ELEMENT:
+ if (!missing_structure_get_string_detail (msg->structure, &detail))
+ goto error;
+ break;
+ case GST_MISSING_TYPE_DECODER:
+ case GST_MISSING_TYPE_ENCODER:{
+ GstCaps *caps = NULL;
+
+ if (!missing_structure_get_caps_detail (msg->structure, &caps))
+ goto error;
+
+ detail = gst_caps_to_string (caps);
+ gst_caps_unref (caps);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ g_string_append_printf (str, "%s-%s", type, detail);
+ g_free (detail);
+
+ return g_string_free (str, FALSE);
+
+/* ERRORS */
+error:
+ {
+ GST_WARNING ("Failed to parse missing-plugin msg: %" GST_PTR_FORMAT, msg);
+ if (str)
+ g_string_free (str, TRUE);
+ return NULL;
+ }
+}
+
+/**
+ * gst_missing_plugin_message_get_description:
+ * @msg: a missing-plugin #GstMessage of type #GST_MESSAGE_ELEMENT
+ *
+ * Returns a localised string describing the missing feature, for use in
+ * error dialogs and the like. Should never return NULL unless @msg is not
+ * a valid missing-plugin message.
+ *
+ * This function is mainly for applications that need a human-readable string
+ * describing a missing plugin, given a previously collected missing-plugin
+ * message
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_missing_plugin_message_get_description (GstMessage * msg)
+{
+ GstMissingType missing_type;
+ const gchar *desc;
+ gchar *ret = NULL;
+
+ g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
+
+ GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, msg->structure);
+
+ desc = gst_structure_get_string (msg->structure, "name");
+ if (desc != NULL && *desc != '\0') {
+ ret = g_strdup (desc);
+ goto done;
+ }
+
+ /* fallback #1 */
+ missing_type = missing_structure_get_type (msg->structure);
+
+ switch (missing_type) {
+ case GST_MISSING_TYPE_URISOURCE:
+ case GST_MISSING_TYPE_URISINK:
+ case GST_MISSING_TYPE_ELEMENT:{
+ gchar *detail = NULL;
+
+ if (missing_structure_get_string_detail (msg->structure, &detail)) {
+ if (missing_type == GST_MISSING_TYPE_URISOURCE)
+ ret = gst_base_utils_get_source_description (detail);
+ else if (missing_type == GST_MISSING_TYPE_URISINK)
+ ret = gst_base_utils_get_sink_description (detail);
+ else
+ ret = gst_base_utils_get_sink_description (detail);
+ g_free (detail);
+ }
+ break;
+ }
+ case GST_MISSING_TYPE_DECODER:
+ case GST_MISSING_TYPE_ENCODER:{
+ GstCaps *caps = NULL;
+
+ if (missing_structure_get_caps_detail (msg->structure, &caps)) {
+ if (missing_type == GST_MISSING_TYPE_DECODER)
+ ret = gst_base_utils_get_decoder_description (caps);
+ else
+ ret = gst_base_utils_get_encoder_description (caps);
+ gst_caps_unref (caps);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (ret)
+ goto done;
+
+ /* fallback #2 */
+ switch (missing_type) {
+ case GST_MISSING_TYPE_URISOURCE:
+ desc = _("Unknown source element");
+ break;
+ case GST_MISSING_TYPE_URISINK:
+ desc = _("Unknown sink element");
+ break;
+ case GST_MISSING_TYPE_ELEMENT:
+ desc = _("Unknown element");
+ break;
+ case GST_MISSING_TYPE_DECODER:
+ desc = _("Unknown decoder element");
+ break;
+ case GST_MISSING_TYPE_ENCODER:
+ desc = _("Unknown encoder element");
+ break;
+ default:
+ /* we should really never get here, but we better still return
+ * something if we do */
+ desc = _("Plugin or element of unknown type");
+ break;
+ }
+ ret = g_strdup (desc);
+
+done:
+
+ GST_LOG ("returning '%s'", ret);
+ return ret;
+}
+
+/**
+ * gst_is_missing_plugin_message:
+ * @msg: a #GstMessage
+ *
+ * Checks whether @msg is a missing plugins message.
+ *
+ * Returns: %TRUE if @msg is a missing-plugins message, otherwise %FALSE.
+ */
+gboolean
+gst_is_missing_plugin_message (GstMessage * msg)
+{
+ g_return_val_if_fail (msg != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_MESSAGE (msg), FALSE);
+
+ if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ELEMENT || msg->structure == NULL)
+ return FALSE;
+
+ return gst_structure_has_name (msg->structure, "missing-plugin");
+}
--- /dev/null
+/* GStreamer base utils library missing plugins support
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_BASE_UTILS_MISSING_PLUGINS_H__
+#define __GST_BASE_UTILS_MISSING_PLUGINS_H__
+
+#include <gst/gstmessage.h>
+#include <gst/gstcaps.h>
+
+G_BEGIN_DECLS
+
+/*
+ * functions to create missing-plugin messages, for use by plugins primarily
+ */
+
+GstMessage * gst_missing_uri_source_message_new (GstElement * element,
+ const gchar * protocol);
+
+GstMessage * gst_missing_uri_sink_message_new (GstElement * element,
+ const gchar * protocol);
+
+GstMessage * gst_missing_element_message_new (GstElement * element,
+ const gchar * factory_name);
+
+GstMessage * gst_missing_decoder_message_new (GstElement * element,
+ const GstCaps * decode_caps);
+
+GstMessage * gst_missing_encoder_message_new (GstElement * element,
+ const GstCaps * encode_caps);
+
+/*
+ * functions for use by the application when dealing with missing-plugin messages
+ */
+
+gchar * gst_missing_plugin_message_get_installer_detail (GstMessage * msg);
+
+gchar * gst_missing_plugin_message_get_description (GstMessage * msg);
+
+gboolean gst_is_missing_plugin_message (GstMessage * msg);
+
+G_END_DECLS
+
+#endif /* __GST_BASE_UTILS_MISSING_PLUGINS_H__ */
+
--- /dev/null
+/* GStreamer base utils library
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "base-utils.h"
+
+#include "gst/gst-i18n-plugin.h"
+
+/**
+ * gst_base_utils_init:
+ *
+ * Initialises the base utils support library. This function is not
+ * thread-safe. Applications should call it after calling gst_init(),
+ * plugins should call it from their plugin_init function.
+ */
+void
+gst_base_utils_init (void)
+{
+ static gboolean inited; /* FALSE */
+
+ if (inited) {
+ GST_LOG ("already initialised");
+ return;
+ }
+#ifdef ENABLE_NLS
+ GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+ LOCALEDIR);
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+
+ inited = TRUE;
+}
--- /dev/null
+/* GStreamer base utils library
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_BASE_UTILS_BASE_UTILS_H__
+#define __GST_BASE_UTILS_BASE_UTILS_H__
+
+#include <gst/gst.h>
+
+#include <gst/utils/descriptions.h>
+#include <gst/utils/missing-plugins.h>
+
+G_BEGIN_DECLS
+
+void gst_base_utils_init (void);
+
+G_END_DECLS
+
+#endif /* __GST_BASE_UTILS_BASE_UTILS_H__ */
+
--- /dev/null
+lib_LTLIBRARIES = libgstbaseutils-@GST_MAJORMINOR@.la
+
+libgstbaseutils_@GST_MAJORMINOR@_la_SOURCES = \
+ base-utils.c \
+ base-utils.h \
+ descriptions.c \
+ descriptions.h \
+ missing-plugins.c \
+ missing-plugins.h
+
+libgstbaseutils_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/utils
+libgstbaseutils_@GST_MAJORMINOR@include_HEADERS = \
+ base-utils.h \
+ descriptions.h \
+ missing-plugins.h
+
+libgstbaseutils_@GST_MAJORMINOR@_la_LIBADD = $(GST_LIBS)
+libgstbaseutils_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstbaseutils_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
--- /dev/null
+/* GStreamer base utils library
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "base-utils.h"
+
+#include "gst/gst-i18n-plugin.h"
+
+/**
+ * gst_base_utils_init:
+ *
+ * Initialises the base utils support library. This function is not
+ * thread-safe. Applications should call it after calling gst_init(),
+ * plugins should call it from their plugin_init function.
+ */
+void
+gst_base_utils_init (void)
+{
+ static gboolean inited; /* FALSE */
+
+ if (inited) {
+ GST_LOG ("already initialised");
+ return;
+ }
+#ifdef ENABLE_NLS
+ GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+ LOCALEDIR);
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+
+ inited = TRUE;
+}
--- /dev/null
+/* GStreamer base utils library
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_BASE_UTILS_BASE_UTILS_H__
+#define __GST_BASE_UTILS_BASE_UTILS_H__
+
+#include <gst/gst.h>
+
+#include <gst/utils/descriptions.h>
+#include <gst/utils/missing-plugins.h>
+
+G_BEGIN_DECLS
+
+void gst_base_utils_init (void);
+
+G_END_DECLS
+
+#endif /* __GST_BASE_UTILS_BASE_UTILS_H__ */
+
--- /dev/null
+/* GStreamer base utils library source/sink/codec description support
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gst/gst-i18n-plugin.h"
+
+#include "base-utils.h"
+
+#include <string.h>
+
+typedef enum
+{
+ FLAG_CONTAINER = (1 << 0), /* format is a container format (muxed) */
+ FLAG_SYSTEMSTREAM = (1 << 1) /* match record only if caps have systemstream=true */
+} FormatFlags;
+
+typedef struct
+{
+ const gchar *type;
+ const gchar *desc;
+ FormatFlags flags;
+} FormatInfo;
+
+static const FormatInfo formats[] = {
+ /* container formats with static descriptions */
+ {"application/ogg", "Ogg", FLAG_CONTAINER},
+ {"application/vnd.rn-realmedia", "Realmedia", FLAG_CONTAINER},
+ {"video/x-fli", "FLI/FLC/FLX Animation", FLAG_CONTAINER},
+ {"video/x-flv", "Flash", FLAG_CONTAINER},
+ {"video/x-matroska", "Matroska", FLAG_CONTAINER},
+ {"video/x-ms-asf", "Advanced Streaming Format (ASF)", FLAG_CONTAINER},
+ {"video/x-msvideo", "AVI", FLAG_CONTAINER},
+ {"video/x-quicktime", "Quicktime", FLAG_CONTAINER},
+ {"video/quicktime", "Quicktime", FLAG_CONTAINER},
+
+ /* audio formats with static descriptions */
+ {"audio/x-ac3", "AC-3 (ATSC A/52)", 0},
+ {"audio/ac3", "AC-3 (ATSC A/52)", 0},
+ {"audio/x-private-ac3", "DVD AC-3 (ATSC A/52)", 0},
+ {"audio/x-private1-ac3", "DVD AC-3 (ATSC A/52)", 0},
+ {"audio/x-adpcm", "ADPCM", 0},
+ {"audio/aiff", "Audio Interchange File Format (AIFF)", 0},
+ {"audio/x-alaw", "A-Law", 0},
+ {"audio/amr", "Adaptive Multi Rate (AMR)", 0},
+ {"audio/AMR", "Adaptive Multi Rate (AMR)", 0},
+ {"audio/AMR-WB", "Adaptive Multi Rate WideBand (AMR-WB)", 0},
+ {"audio/iLBC-sh", "Internet Low Bitrate Codec (iLBC)", 0},
+ {"audio/ms-gsm", "MS GSM", 0},
+ {"audio/qcelp", "QCELP", 0},
+ {"audio/x-adpcm", "ADPCM", 0}, /* TODO: different variants */
+ {"audio/x-aiff", "Audio Interchange File Format (AIFF)", 0},
+ {"audio/x-alac", N_("Apple Lossless Audio (ALAC)"), 0},
+ {"audio/x-amr-nb-sh", "Adaptive Multi Rate NarrowBand (AMR-NB)", 0},
+ {"audio/x-amr-wb-sh", "Adaptive Multi Rate WideBand (AMR-WB)", 0},
+ {"audio/x-au", "Sun .au", 0},
+ {"audio/x-cinepak", "Cinepak Audio", 0},
+ {"audio/x-dpcm", "DPCM", 0},
+ {"audio/x-dts", "DTS", 0},
+ {"audio/x-dv", "DV Audio", 0},
+ {"audio/x-flac", N_("Free Lossless Audio Codec (FLAC)"), 0},
+ {"audio/x-gsm", "GSM", 0},
+ {"audio/x-iec958", "S/PDIF IEC958", 0}, /* TODO: check description */
+ {"audio/x-iLBC", "Internet Low Bitrate Codec (iLBC)", 0},
+ {"audio/x-ircam", "Berkeley/IRCAM/CARL", 0},
+ {"audio/x-lpcm", "LPCM", 0},
+ {"audio/x-private1-lpcm", "DVD LPCM", 0},
+ {"audio/x-m4a", "MPEG-4 AAC", FLAG_CONTAINER},
+ {"audio/x-mod", "Module Music Format (MOD)", 0},
+ {"audio/x-mulaw", "Mu-Law", 0},
+ {"audio/x-musepack", "Musepack (MPC)", 0},
+ {"audio/x-nist", "Sphere NIST", 0},
+ {"audio/x-nsf", "Nintendo NSF", 0},
+ {"audio/x-paris", "Ensoniq PARIS", 0},
+ {"audio/x-qdm2", "QDesign Music (QDM) 2", 0},
+ {"audio/x-ralf-mpeg4-generic", "Real Audio Lossless (RALF)", 0},
+ {"audio/x-sds", "SDS", 0},
+ {"audio/x-shorten", "Shorten Lossless", 0},
+ {"audio/x-sid", "Sid", 0},
+ {"audio/x-sipro", "Sipro/ACELP.NET Voice", 0},
+ {"audio/x-spc", "SNES-SPC700 Sound File Data", 0},
+ {"audio/x-speex", "Speex", 0},
+ {"audio/x-svx", "Amiga IFF / SVX8 / SV16", 0},
+ {"audio/x-tta", N_("Lossless True Audio (TTA)"), 0},
+ {"audio/x-ttafile", N_("Lossless True Audio (TTA)"), 0},
+ {"audio/x-vnd.sony.atrac3", "Sony ATRAC3", 0},
+ {"audio/x-vorbis", "Vorbis", 0},
+ {"audio/x-voc", "SoundBlaster VOC", 0},
+ {"audio/x-w64", "Sonic Foundry Wave64", 0},
+ {"audio/x-wav", "WAV", 0},
+ {"audio/x-wavpack", "Wavpack", 0},
+ {"audio/x-wavpack-correction", "Wavpack", 0},
+ {"audio/x-wms", N_("Windows Media Speech"), 0},
+ {"audio/x-voxware", "Voxware", 0},
+
+
+ /* video formats with static descriptions */
+ {"video/sp5x", "Sunplus JPEG 5.x", 0},
+ {"video/vivo", "Vivo", 0},
+ {"video/x-3ivx", "3ivx", 0},
+ {"video/x-4xm", "4X Techologies Video", 0},
+ {"video/x-apple-video", "Apple video", 0},
+ {"video/x-camtasia", "TechSmith Camtasia", 0},
+ {"video/x-cdxa", "RIFF/CDXA (VCD)", 0},
+ {"video/x-cinepak", "Cinepak Video", 0},
+ {"video/x-cirrus-logic-accupak", "Cirrus Logipak AccuPak", 0},
+ {"video/x-compressed-yuv", N_("CYUV Lossless"), 0},
+ {"video/x-dirac", "Dirac", 0},
+ {"video/x-dvd-subpicture", "DVD subpicture", 0},
+ {"video/x-ffv", N_("FFMpeg v1"), 0},
+ {"video/x-flash-screen", "Flash Screen Video", 0},
+ {"video/x-flash-video", "Flash Video", 0},
+ {"video/x-h261", "H.261", 0},
+ {"video/x-huffyuv", "Huffyuv", 0},
+ {"video/x-intel-h263", "Intel H.263", 0},
+ {"video/x-jpeg", "Motion JPEG", 0},
+ /* { "video/x-jpeg-b", "", 0 }, does this actually exist? */
+ {"video/x-mjpeg", "Motion-JPEG", 0},
+ {"video/x-mjpeg-b", "Motion-JPEG format B", 0},
+ {"video/mpegts", "MPEG-2 Transport Stream", FLAG_CONTAINER},
+ {"video/x-mng", "Multiple Image Network Graphics (MNG)", 0},
+ {"video/x-mszh", N_("Lossless MSZH"), 0},
+ {"video/x-msvideocodec", "Microsoft Video 1", 0},
+ {"video/x-mve", "Interplay MVE", FLAG_CONTAINER},
+ {"video/x-nut", "NUT", FLAG_CONTAINER},
+ {"video/x-nuv", "MythTV NuppelVideo (NUV)", FLAG_CONTAINER},
+ {"video/x-qdrw", "Apple QuickDraw", 0},
+ {"video/x-raw-gray", N_("Uncompressed Gray Image"), 0},
+ {"video/x-smc", "Apple SMC", 0},
+ {"video/x-smoke", "Smoke", 0},
+ {"video/x-tarkin", "Tarkin", 0},
+ {"video/x-theora", "Theora", 0},
+ {"video/x-rle", N_("Run-length encoding"), 0},
+ {"video/x-ultimotion", "IBM UltiMotion", 0},
+ {"video/x-vcd", "VideoCD (VCD)", 0},
+ {"video/x-vmnc", "VMWare NC", 0},
+ {"video/x-vp3", "On2 VP3", 0},
+ {"video/x-vp5", "On2 VP5", 0},
+ {"video/x-vp6", "On2 VP6", 0},
+ {"video/x-vp6-flash", "On2 VP6/Flash", 0},
+ {"video/x-vp7", "On2 VP7", 0},
+ {"video/x-xvid", "XVID MPEG-4", 0},
+ {"video/x-zlib", "Lossless zlib video", 0},
+
+ /* image formats with static descriptions */
+ {"image/bmp", "BMP", 0},
+ {"image/x-bmp", "BMP", 0},
+ {"image/x-MS-bmp", "BMP", 0},
+ {"image/gif", "GIF", 0},
+ {"image/jpeg", "JPEG", 0},
+ {"image/jng", "JPEG Network Graphics (JNG)", 0},
+ {"image/png", "PNG", 0},
+ {"image/pbm", "PBM", 0},
+ {"image/ppm", "PPM", 0},
+ {"image/svg+xml", "Scalable Vector Graphics (SVG)", 0},
+ {"image/tiff", "TIFF", 0},
+ {"image/x-cmu-raster", "CMU Raster Format", 0},
+ {"image/x-icon", "ICO", 0},
+ {"image/x-xcf", "XFC", 0},
+ {"image/x-pixmap", "XPM", 0},
+ {"image/x-xpixmap", "XPM", 0},
+ {"image/x-quicktime", "QuickTime Image Format (QTIF)", 0},
+ {"image/x-sun-raster", "Sun Raster Format (RAS)", 0},
+ {"image/x-tga", "TGA", 0},
+
+ /* formats with dynamic descriptions */
+ {"audio/mpeg", NULL, 0},
+ {"audio/x-mace", NULL, 0},
+ {"audio/x-pn-realaudio", NULL, 0},
+ {"audio/x-raw-int", NULL, 0},
+ {"audio/x-raw-float", NULL, 0},
+ {"audio/x-wma", NULL, 0},
+ {"video/mpeg", NULL, FLAG_CONTAINER | FLAG_SYSTEMSTREAM},
+ {"video/mpeg", NULL, 0},
+ {"video/x-asus", NULL, 0},
+ {"video/x-ati-vcr", NULL, 0},
+ {"video/x-divx", NULL, 0},
+ {"video/x-dv", "Digital Video (DV) System Stream",
+ FLAG_CONTAINER | FLAG_SYSTEMSTREAM},
+ {"video/x-dv", "Digital Video (DV)", 0},
+ {"video/x-h263", NULL, 0},
+ {"video/x-h264", NULL, 0},
+ {"video/x-indeo", NULL, 0},
+ {"video/x-msmpeg", NULL, 0},
+ {"video/x-pn-realvideo", NULL, 0},
+#if 0
+ /* do these exist? are they used anywhere? */
+ {"video/x-pn-multirate-realvideo", NULL, 0},
+ {"audio/x-pn-multirate-realaudio", NULL, 0},
+ {"audio/x-pn-multirate-realaudio-live", NULL, 0},
+#endif
+ {"video/x-truemotion", NULL, 0},
+ {"video/x-raw-rgb", NULL, 0},
+ {"video/x-raw-yuv", NULL, 0},
+ {"video/x-svq", NULL, 0},
+ {"video/x-wmv", NULL, 0},
+ {"video/x-xan", NULL, 0}
+};
+
+/* returns static descriptions and dynamic ones (such as video/x-raw-yuv),
+ * or NULL if caps aren't known at all */
+static gchar *
+format_info_get_desc (const FormatInfo * info, const GstCaps * caps)
+{
+ const GstStructure *s;
+
+ g_assert (info != NULL);
+
+ if (info->desc != NULL)
+ return g_strdup (_(info->desc));
+
+ s = gst_caps_get_structure (caps, 0);
+
+ if (strcmp (info->type, "video/x-raw-yuv") == 0) {
+ const gchar *ret = NULL;
+ guint32 fourcc = 0;
+
+ gst_structure_get_fourcc (s, "format", &fourcc);
+ switch (fourcc) {
+ case GST_MAKE_FOURCC ('I', '4', '2', '0'):
+ ret = _("Uncompressed planar YUV 4:2:0");
+ break;
+ case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
+ ret = _("Uncompressed planar YVU 4:2:0");
+ break;
+ case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
+ ret = _("Uncompressed packed YUV 4:2:2");
+ break;
+ case GST_MAKE_FOURCC ('Y', 'U', 'V', '9'):
+ ret = _("Uncompressed packed YUV 4:1:0");
+ break;
+ case GST_MAKE_FOURCC ('Y', 'V', 'U', '9'):
+ ret = _("Uncompressed packed YVU 4:1:0");
+ break;
+ case GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U'):
+ case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
+ ret = _("Uncompressed packed YUV 4:2:2");
+ break;
+ case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
+ ret = _("Uncompressed packed YUV 4:1:1");
+ break;
+ case GST_MAKE_FOURCC ('I', 'Y', 'U', '2'):
+ ret = _("Uncompressed packed YUV 4:4:4");
+ break;
+ case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
+ ret = _("Uncompressed planar YUV 4:2:2");
+ break;
+ case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
+ ret = _("Uncompressed planar YUV 4:1:1");
+ break;
+ case GST_MAKE_FOURCC ('Y', '8', '0', '0'):
+ ret = _("Uncompressed black and white Y-plane");
+ break;
+ default:
+ ret = _("Uncompressed YUV");
+ break;
+ }
+ return g_strdup (ret);
+ } else if (strcmp (info->type, "video/x-raw-rgb") == 0) {
+ const gchar *rgb_str;
+ gint depth = 0;
+
+ gst_structure_get_int (s, "depth", &depth);
+ rgb_str = gst_structure_has_field (s, "alpha_mask") ? "RGBA" : "RGB";
+ if (gst_structure_has_field (s, "paletted_data")) {
+ return g_strdup_printf (_("Uncompressed palettized %d-bit %s"), depth,
+ rgb_str);
+ } else {
+ return g_strdup_printf ("Uncompressed %d-bit %s", depth, rgb_str);
+ }
+ } else if (strcmp (info->type, "video/x-h263") == 0) {
+ const gchar *variant, *ret;
+
+ variant = gst_structure_get_string (s, "variant");
+ if (variant == NULL)
+ ret = "H.263";
+ else if (strcmp (variant, "itu") == 0)
+ ret = "ITU H.26n"; /* why not ITU H.263? (tpm) */
+ else if (strcmp (variant, "lead") == 0)
+ ret = "Lead H.263";
+ else if (strcmp (variant, "microsoft") == 0)
+ ret = "Microsoft H.263";
+ else if (strcmp (variant, "vdolive") == 0)
+ ret = "VDOLive";
+ else if (strcmp (variant, "vivo") == 0)
+ ret = "Vivo H.263";
+ else if (strcmp (variant, "xirlink") == 0)
+ ret = "Xirlink H.263";
+ else {
+ GST_WARNING ("Unknown H263 variant '%s'", variant);
+ ret = "H.263";
+ }
+ return g_strdup (ret);
+ } else if (strcmp (info->type, "video/x-h264") == 0) {
+ const gchar *variant, *ret;
+
+ variant = gst_structure_get_string (s, "variant");
+ if (variant == NULL)
+ ret = "H.264";
+ else if (strcmp (variant, "itu") == 0)
+ ret = "ITU H.264";
+ else if (strcmp (variant, "videosoft") == 0)
+ ret = "Videosoft H.264";
+ else {
+ GST_WARNING ("Unknown H264 variant '%s'", variant);
+ ret = "H.264";
+ }
+ return g_strdup (ret);
+ } else if (strcmp (info->type, "video/x-divx") == 0) {
+ gint ver = 0;
+
+ if (!gst_structure_get_int (s, "divxversion", &ver) || ver <= 2) {
+ GST_WARNING ("Unexpected DivX version in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("DivX MPEG-4");
+ }
+ return g_strdup_printf (_("DivX MPEG-4 Version %d"), ver);
+ } else if (strcmp (info->type, "video/x-msmpeg") == 0) {
+ gint ver = 0;
+
+ if (!gst_structure_get_int (s, "msmpegversion", &ver) ||
+ ver < 40 || ver > 49) {
+ GST_WARNING ("Unexpected msmpegversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Microsoft MPEG-4 4.x");
+ }
+ return g_strdup_printf ("Microsoft MPEG-4 4.%d", ver % 10);
+ } else if (strcmp (info->type, "video/x-truemotion") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "trueversion", &ver);
+ switch (ver) {
+ case 1:
+ return g_strdup_printf ("Duck TrueMotion 1");
+ case 2:
+ return g_strdup_printf ("TrueMotion 2.0");
+ default:
+ GST_WARNING ("Unexpected trueversion in %" GST_PTR_FORMAT, caps);
+ break;
+ }
+ return g_strdup_printf ("TrueMotion");
+ } else if (strcmp (info->type, "video/x-xan") == 0) {
+ gint ver = 0;
+
+ if (!gst_structure_get_int (s, "wcversion", &ver) || ver < 1) {
+ GST_WARNING ("Unexpected wcversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Xan Wing Commander");
+ }
+ return g_strdup_printf ("Xan Wing Commander %u", ver);
+ } else if (strcmp (info->type, "video/x-indeo") == 0) {
+ gint ver = 0;
+
+ if (!gst_structure_get_int (s, "indeoversion", &ver) || ver < 2) {
+ GST_WARNING ("Unexpected indeoversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Intel Indeo");
+ }
+ return g_strdup_printf ("Intel Indeo %u", ver);
+ } else if (strcmp (info->type, "audio/x-wma") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "wmaversion", &ver);
+ switch (ver) {
+ case 1:
+ case 2:
+ case 3:
+ return g_strdup_printf ("Windows Media Audio %d", ver + 6);
+ default:
+ break;
+ }
+ GST_WARNING ("Unexpected wmaversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Windows Media Audio");
+ } else if (strcmp (info->type, "video/x-wmv") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "wmvversion", &ver);
+ switch (ver) {
+ case 1:
+ case 2:
+ case 3:
+ return g_strdup_printf ("Windows Media Video %d", ver + 6);
+ default:
+ break;
+ }
+ GST_WARNING ("Unexpected wmvversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Windows Media Video");
+ } else if (strcmp (info->type, "audio/x-mace") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "maceversion", &ver);
+ if (ver == 3 || ver == 6) {
+ return g_strdup_printf ("MACE-%d", ver);
+ } else {
+ GST_WARNING ("Unexpected maceversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("MACE");
+ }
+ } else if (strcmp (info->type, "video/x-svq") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "svqversion", &ver);
+ if (ver == 1 || ver == 3) {
+ return g_strdup_printf ("Sorensen Video %d", ver);
+ } else {
+ GST_WARNING ("Unexpected svqversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Sorensen Video");
+ }
+ } else if (strcmp (info->type, "video/x-asus") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "asusversion", &ver);
+ if (ver == 1 || ver == 2) {
+ return g_strdup_printf ("Asus Video %d", ver);
+ } else {
+ GST_WARNING ("Unexpected asusversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("Asus Video");
+ }
+ } else if (strcmp (info->type, "video/x-ati-vcr") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "vcrversion", &ver);
+ if (ver == 1 || ver == 2) {
+ return g_strdup_printf ("ATI VCR %d", ver);
+ } else {
+ GST_WARNING ("Unexpected acrversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("ATI VCR");
+ }
+ } else if (strcmp (info->type, "audio/mpeg") == 0) {
+ gint ver = 0, layer = 0;
+
+ gst_structure_get_int (s, "mpegversion", &ver);
+
+ switch (ver) {
+ case 1:
+ gst_structure_get_int (s, "layer", &layer);
+ switch (layer) {
+ case 1:
+ case 2:
+ case 3:
+ return g_strdup_printf ("MPEG-1 Layer %d (MP%d)", layer, layer);
+ default:
+ break;
+ }
+ GST_WARNING ("Unexpected MPEG-1 layer in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("MPEG-1 Audio");
+ case 4:
+ return g_strdup ("MPEG-4 AAC");
+ default:
+ break;
+ }
+ GST_WARNING ("Unexpected audio mpegversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("MPEG Audio");
+ } else if (strcmp (info->type, "audio/x-pn-realaudio") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "raversion", &ver);
+ switch (ver) {
+ case 1:
+ return g_strdup ("RealAudio 14k4bps");
+ case 2:
+ return g_strdup ("RealAudio 28k8bps");
+ case 8:
+ return g_strdup ("RealAudio G2 (Cook)");
+ default:
+ break;
+ }
+ GST_WARNING ("Unexpected raversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("RealAudio");
+ } else if (strcmp (info->type, "video/x-pn-realvideo") == 0) {
+ gint ver = 0;
+
+ gst_structure_get_int (s, "rmversion", &ver);
+ switch (ver) {
+ case 1:
+ return g_strdup ("RealVideo 1.0");
+ case 2:
+ return g_strdup ("RealVideo 2.0");
+ case 3:
+ return g_strdup ("RealVideo 3.0");
+ case 4:
+ return g_strdup ("RealVideo 4.0");
+ default:
+ break;
+ }
+ GST_WARNING ("Unexpected rmversion in %" GST_PTR_FORMAT, caps);
+ return g_strdup ("RealVideo");
+ } else if (strcmp (info->type, "video/mpeg") == 0) {
+ gboolean sysstream;
+ gint ver = 0;
+
+ if (!gst_structure_get_boolean (s, "systemstream", &sysstream) ||
+ !gst_structure_get_int (s, "mpegversion", &ver) || ver < 1 || ver > 4) {
+ GST_WARNING ("Missing fields in mpeg video caps %" GST_PTR_FORMAT, caps);
+ } else {
+ if (sysstream) {
+ return g_strdup_printf ("MPEG-%d System Stream", ver);
+ } else {
+ return g_strdup_printf ("MPEG-%d Video", ver);
+ }
+ }
+ return g_strdup ("MPEG Video");
+ } else if (strcmp (info->type, "audio/x-raw-int") == 0) {
+ gint bitdepth = 0;
+
+ /* 8-bit pcm might not have depth field (?) */
+ if (!gst_structure_get_int (s, "depth", &bitdepth))
+ gst_structure_get_int (s, "width", &bitdepth);
+ if (bitdepth != 0)
+ return g_strdup_printf (_("Raw %d-bit PCM audio"), bitdepth);
+ else
+ return g_strdup (_("Raw PCM audio"));
+ } else if (strcmp (info->type, "audio/x-raw-float") == 0) {
+ gint bitdepth = 0;
+
+ gst_structure_get_int (s, "width", &bitdepth);
+ if (bitdepth != 0)
+ return g_strdup_printf (_("Raw %d-bit floating-point audio"), bitdepth);
+ else
+ return g_strdup (_("Raw floating-point audio"));
+ }
+
+ return NULL;
+}
+
+/* returns format info structure, will return NULL for dynamic media types! */
+static const FormatInfo *
+find_format_info (const GstCaps * caps)
+{
+ const GstStructure *s;
+ const gchar *media_type;
+ guint i;
+
+ s = gst_caps_get_structure (caps, 0);
+ media_type = gst_structure_get_name (s);
+
+ for (i = 0; i < G_N_ELEMENTS (formats); ++i) {
+ if (strcmp (media_type, formats[i].type) == 0) {
+ gboolean is_sys = FALSE;
+
+ if ((formats[i].flags & FLAG_SYSTEMSTREAM) == 0)
+ return &formats[i];
+
+ /* this record should only be matched if the systemstream field is set */
+ if (gst_structure_get_boolean (s, "systemstream", &is_sys) && is_sys)
+ return &formats[i];
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean
+caps_are_rtp_caps (const GstCaps * caps, const gchar * media, gchar ** format)
+{
+ const GstStructure *s;
+ const gchar *str;
+
+ g_assert (media != NULL && format != NULL);
+
+ s = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_has_name (s, "application/x-rtp"))
+ return FALSE;
+ if (!gst_structure_has_field_typed (s, "media", G_TYPE_STRING))
+ return FALSE;
+ str = gst_structure_get_string (s, "media");
+ if (str == NULL || !g_str_equal (str, media))
+ return FALSE;
+ str = gst_structure_get_string (s, "encoding-name");
+ if (str == NULL || *str == '\0')
+ return FALSE;
+ *format = g_strdup (str);
+ return TRUE;
+}
+
+/**
+ * gst_base_utils_get_source_description:
+ * @protocol: the protocol the source element needs to handle, e.g. "http"
+ *
+ * Returns a localised string describing a source element handling the protocol
+ * specified in @protocol, for use in error dialogs or other messages to be
+ * seen by the user. Should never return NULL unless @protocol is invalid.
+ *
+ * This function is mainly for internal use, applications would typically
+ * use gst_missing_plugin_message_get_description() to get a description of
+ * a missing feature from a missing-plugin message.
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_base_utils_get_source_description (const gchar * protocol)
+{
+ gchar *proto_uc, *ret;
+
+ g_return_val_if_fail (protocol != NULL, NULL);
+
+ if (strcmp (protocol, "cdda") == 0)
+ return g_strdup (_("Audio CD source"));
+
+ if (strcmp (protocol, "dvd") == 0)
+ return g_strdup (_("DVD source"));
+
+ if (strcmp (protocol, "rtsp") == 0)
+ return g_strdup (_("Real Time Streaming Protocol (RTSP) source"));
+
+ /* TODO: what about mmst, mmsu, mmsh? */
+ if (strcmp (protocol, "mms") == 0)
+ return g_strdup (_("Microsoft Media Server (MMS) protocol source"));
+
+ /* make protocol uppercase */
+ proto_uc = g_ascii_strup (protocol, -1);
+
+ /* TODO: find out how to add a comment for translators to the source code
+ * (and tell them to make the first letter uppercase below if they move
+ * the protocol to the middle or end of the string) */
+ ret = g_strdup_printf (_("%s protocol source"), proto_uc);
+
+ g_free (proto_uc);
+
+ return ret;
+}
+
+/**
+ * gst_base_utils_get_sink_description:
+ * @protocol: the protocol the sink element needs to handle, e.g. "http"
+ *
+ * Returns a localised string describing a sink element handling the protocol
+ * specified in @protocol, for use in error dialogs or other messages to be
+ * seen by the user. Should never return NULL unless @protocol is invalid.
+ *
+ * This function is mainly for internal use, applications would typically
+ * use gst_missing_plugin_message_get_description() to get a description of
+ * a missing feature from a missing-plugin message.
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_base_utils_get_sink_description (const gchar * protocol)
+{
+ gchar *proto_uc, *ret;
+
+ g_return_val_if_fail (protocol != NULL, NULL);
+
+ /* make protocol uppercase */
+ proto_uc = g_ascii_strup (protocol, -1);
+
+ /* TODO: find out how to add a comment for translators to the source code
+ * (and tell them to make the first letter uppercase below if they move
+ * the protocol to the middle or end of the string) */
+ ret = g_strdup_printf ("%s protocol sink", proto_uc);
+
+ g_free (proto_uc);
+
+ return ret;
+}
+
+/**
+ * gst_base_utils_get_decoder_description:
+ * @caps: the (fixed) #GstCaps for which an decoder description is needed
+ *
+ * Returns a localised string describing an decoder for the format specified
+ * in @caps, for use in error dialogs or other messages to be seen by the user.
+ * Should never return NULL unless @factory_name or @caps are invalid.
+ *
+ * This function is mainly for internal use, applications would typically
+ * use gst_missing_plugin_message_get_description() to get a description of
+ * a missing feature from a missing-plugin message.
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_base_utils_get_decoder_description (const GstCaps * caps)
+{
+ gchar *str, *ret;
+
+ g_return_val_if_fail (caps != NULL, NULL);
+ g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
+ g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
+
+ /* special-case RTP caps */
+ if (caps_are_rtp_caps (caps, "video", &str)) {
+ ret = g_strdup_printf (_("%s video RTP depayloader"), str);
+ } else if (caps_are_rtp_caps (caps, "audio", &str)) {
+ ret = g_strdup_printf (_("%s audio RTP depayloader"), str);
+ } else if (caps_are_rtp_caps (caps, "application", &str)) {
+ ret = g_strdup_printf (_("%s RTP depayloader"), str);
+ } else {
+ const FormatInfo *info;
+
+ str = gst_base_utils_get_codec_description (caps);
+ info = find_format_info (caps);
+ if (info != NULL && (info->flags & FLAG_CONTAINER) != 0) {
+ ret = g_strdup_printf (_("%s demuxer"), str);
+ } else {
+ ret = g_strdup_printf (_("%s decoder"), str);
+ }
+ }
+
+ g_free (str);
+
+ return ret;
+}
+
+/**
+ * gst_base_utils_get_encoder_description:
+ * @caps: the (fixed) #GstCaps for which an encoder description is needed
+ *
+ * Returns a localised string describing an encoder for the format specified
+ * in @caps, for use in error dialogs or other messages to be seen by the user.
+ * Should never return NULL unless @factory_name or @caps are invalid.
+ *
+ * This function is mainly for internal use, applications would typically
+ * use gst_missing_plugin_message_get_description() to get a description of
+ * a missing feature from a missing-plugin message.
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_base_utils_get_encoder_description (const GstCaps * caps)
+{
+ gchar *str, *ret;
+
+ g_return_val_if_fail (caps != NULL, NULL);
+ g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
+ g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
+
+ /* special-case RTP caps */
+ if (caps_are_rtp_caps (caps, "video", &str)) {
+ ret = g_strdup_printf (_("%s video RTP payloader"), str);
+ } else if (caps_are_rtp_caps (caps, "audio", &str)) {
+ ret = g_strdup_printf (_("%s audio RTP payloader"), str);
+ } else if (caps_are_rtp_caps (caps, "application", &str)) {
+ ret = g_strdup_printf (_("%s RTP payloader"), str);
+ } else {
+ const FormatInfo *info;
+
+ str = gst_base_utils_get_codec_description (caps);
+ info = find_format_info (caps);
+ if (info != NULL && (info->flags & FLAG_CONTAINER) != 0) {
+ ret = g_strdup_printf (_("%s muxer"), str);
+ } else {
+ ret = g_strdup_printf (_("%s encoder"), str);
+ }
+ }
+
+ g_free (str);
+
+ return ret;
+}
+
+/**
+ * gst_base_utils_get_element_description:
+ * @factory_name: the name of the element, e.g. "gnomevfssrc"
+ *
+ * Returns a localised string describing the given element, for use in
+ * error dialogs or other messages to be seen by the user. Should never
+ * return NULL unless @factory_name is invalid.
+ *
+ * This function is mainly for internal use, applications would typically
+ * use gst_missing_plugin_message_get_description() to get a description of
+ * a missing feature from a missing-plugin message.
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_base_utils_get_element_description (const gchar * factory_name)
+{
+ gchar *ret;
+
+ g_return_val_if_fail (factory_name != NULL, NULL);
+
+ ret = g_strdup_printf (_("GStreamer element %s"), factory_name);
+ if (ret && g_str_has_prefix (ret, factory_name))
+ *ret = g_ascii_toupper (*ret);
+
+ return ret;
+}
+
+/**
+ * gst_base_utils_add_codec_description_to_tag_list:
+ * @taglist: a #GstTagList
+ * @codec_tag: a GStreamer codec tag such as #GST_TAG_AUDIO_CODEC,
+ * #GST_TAG_VIDEO_CODEC or #GST_TAG_CODEC
+ * @caps: the (fixed) #GstCaps for which a codec tag should be added.
+ *
+ * Adds a codec tag describing the format specified by @caps to @taglist.
+ *
+ * Returns: TRUE if a codec tag was added, FALSE otherwise.
+ */
+gboolean
+gst_base_utils_add_codec_description_to_tag_list (GstTagList * taglist,
+ const gchar * codec_tag, const GstCaps * caps)
+{
+ const FormatInfo *info;
+ gchar *desc;
+
+ g_return_val_if_fail (taglist != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_TAG_LIST (taglist), FALSE);
+ g_return_val_if_fail (codec_tag != NULL, FALSE);
+ g_return_val_if_fail (gst_tag_exists (codec_tag), FALSE);
+ g_return_val_if_fail (gst_tag_get_type (codec_tag) == G_TYPE_STRING, FALSE);
+ g_return_val_if_fail (caps != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
+
+ info = find_format_info (caps);
+ if (info == NULL)
+ return FALSE;
+
+ desc = format_info_get_desc (info, caps);
+ gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, codec_tag, desc, NULL);
+ g_free (desc);
+
+ return TRUE;
+}
+
+/**
+ * gst_base_utils_get_codec_description:
+ * @caps: the (fixed) #GstCaps for which an format description is needed
+ *
+ * Returns a localised (as far as this is possible) string describing the
+ * media format specified in @caps, for use in error dialogs or other messages
+ * to be seen by the user. Should never return NULL unless @caps is invalid.
+ *
+ * Also see the convenience function
+ * gst_base_utils_add_codec_description_to_tag_list().
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_base_utils_get_codec_description (const GstCaps * caps)
+{
+ const FormatInfo *info;
+ gchar *str, *comma;
+
+ g_return_val_if_fail (caps != NULL, NULL);
+ g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
+ g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
+
+ info = find_format_info (caps);
+
+ if (info) {
+ str = format_info_get_desc (info, caps);
+ } else {
+ str = gst_caps_to_string (caps);
+
+ /* cut off everything after the media type, if there is anything */
+ if ((comma = strchr (str, ','))) {
+ *comma = '\0';
+ g_strchomp (str);
+ /* we could do something more elaborate here, like taking into account
+ * audio/, video/, image/ and application/ prefixes etc. */
+ }
+
+ GST_WARNING ("No description available for media type: %s", str);
+ }
+
+ return str;
+}
+
+#if 0
+void
+gst_base_utils_list_all (void)
+{
+ gint i;
+
+ g_print ("static const gchar *caps_strings[] = { ");
+
+ for (i = 0; i < G_N_ELEMENTS (formats); ++i) {
+ if (formats[i].desc != NULL)
+ g_print (" \"%s\", ", formats[i].type);
+ }
+ g_print ("\n#if 0\n");
+ for (i = 0; i < G_N_ELEMENTS (formats); ++i) {
+ if (formats[i].desc == NULL)
+ g_print (" \"%s\", \n", formats[i].type);
+ }
+ g_print ("\n#endif\n");
+}
+#endif
--- /dev/null
+/* GStreamer base utils library source/sink/codec description support
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_BASE_UTILS_DESCRIPTIONS_H__
+#define __GST_BASE_UTILS_DESCRIPTIONS_H__
+
+#include <gst/gsttaglist.h>
+#include <gst/gstcaps.h>
+
+G_BEGIN_DECLS
+
+/*
+ * functions for use by demuxers or decoders to add CODEC tags to tag lists
+ * from caps
+ */
+
+gboolean gst_base_utils_add_codec_description_to_tag_list (GstTagList * taglist,
+ const gchar * codec_tag,
+ const GstCaps * caps);
+
+gchar * gst_base_utils_get_codec_description (const GstCaps * caps);
+
+/*
+ * functions mainly used by the missing plugins message creation functions to
+ * find descriptions of what exactly is missing
+ */
+
+gchar * gst_base_utils_get_source_description (const gchar * protocol);
+
+gchar * gst_base_utils_get_sink_description (const gchar * protocol);
+
+gchar * gst_base_utils_get_decoder_description (const GstCaps * caps);
+
+gchar * gst_base_utils_get_encoder_description (const GstCaps * caps);
+
+gchar * gst_base_utils_get_element_description (const gchar * factory_name);
+
+
+G_END_DECLS
+
+#endif /* __GST_BASE_UTILS_DESCRIPTIONS_H__ */
+
--- /dev/null
+/* GStreamer base utils library missing plugins support
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> /* getpid on UNIX */
+#endif
+#ifdef HAVE_PROCESS_H
+# include <process.h> /* getpid on win32 */
+#endif
+
+#include "gst/gst-i18n-plugin.h"
+
+#include "base-utils.h"
+
+#include <string.h>
+
+#define GST_DETAIL_STRING_MARKER "gstreamer.net"
+
+typedef enum
+{
+ GST_MISSING_TYPE_UNKNOWN = 0,
+ GST_MISSING_TYPE_URISOURCE,
+ GST_MISSING_TYPE_URISINK,
+ GST_MISSING_TYPE_ELEMENT,
+ GST_MISSING_TYPE_DECODER,
+ GST_MISSING_TYPE_ENCODER
+} GstMissingType;
+
+static const struct
+{
+ GstMissingType type;
+ const gchar type_string[12];
+} missing_type_mapping[] = {
+ {
+ GST_MISSING_TYPE_URISOURCE, "urisource"}, {
+ GST_MISSING_TYPE_URISINK, "urisink"}, {
+ GST_MISSING_TYPE_ELEMENT, "element"}, {
+ GST_MISSING_TYPE_DECODER, "decoder"}, {
+ GST_MISSING_TYPE_ENCODER, "encoder"}
+};
+
+static GstMissingType
+missing_structure_get_type (const GstStructure * s)
+{
+ const gchar *type;
+ guint i;
+
+ type = gst_structure_get_string (s, "type");
+ g_return_val_if_fail (type != NULL, GST_MISSING_TYPE_UNKNOWN);
+
+ for (i = 0; i < G_N_ELEMENTS (missing_type_mapping); ++i) {
+ if (strcmp (missing_type_mapping[i].type_string, type) == 0)
+ return missing_type_mapping[i].type;
+ }
+
+ return GST_MISSING_TYPE_UNKNOWN;
+}
+
+static GstCaps *
+copy_and_clean_caps (const GstCaps * caps)
+{
+ GstStructure *s;
+ GstCaps *ret;
+
+ ret = gst_caps_copy (caps);
+
+ /* make caps easier to interpret, remove common fields that are likely
+ * to be irrelevant for determining the right plugin (ie. mostly fields
+ * where template caps usually have the standard MIN - MAX range as value) */
+ s = gst_caps_get_structure (ret, 0);
+ gst_structure_remove_field (s, "codec_data");
+ gst_structure_remove_field (s, "palette_data");
+ gst_structure_remove_field (s, "pixel-aspect-ratio");
+ gst_structure_remove_field (s, "framerate");
+ /* maybe remove width/height too? */
+
+ return ret;
+}
+
+/**
+ * gst_missing_uri_source_message_new:
+ * @element: the #GstElement posting the message
+ * @protocol: the URI protocol the missing source needs to implement,
+ * e.g. "http" or "mms"
+ *
+ * Creates a missing-plugin message for @element to notify the application
+ * that a source element for a particular URI protocol is missing. This
+ * function is mainly for use in plugins.
+ *
+ * Returns: a new #GstMessage, or NULL on error
+ */
+GstMessage *
+gst_missing_uri_source_message_new (GstElement * element,
+ const gchar * protocol)
+{
+ GstStructure *s;
+ gchar *description;
+
+ g_return_val_if_fail (element != NULL, NULL);
+ g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+ g_return_val_if_fail (protocol != NULL, NULL);
+
+ description = gst_base_utils_get_source_description (protocol);
+
+ s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
+ "urisource", "detail", G_TYPE_STRING, protocol, "name", G_TYPE_STRING,
+ description, NULL);
+
+ g_free (description);
+ return gst_message_new_element (GST_OBJECT_CAST (element), s);
+}
+
+/**
+ * gst_missing_uri_sink_message_new:
+ * @element: the #GstElement posting the message
+ * @protocol: the URI protocol the missing sink needs to implement,
+ * e.g. "http" or "smb"
+ *
+ * Creates a missing-plugin message for @element to notify the application
+ * that a sink element for a particular URI protocol is missing. This
+ * function is mainly for use in plugins.
+ *
+ * Returns: a new #GstMessage, or NULL on error
+ */
+GstMessage *
+gst_missing_uri_sink_message_new (GstElement * element, const gchar * protocol)
+{
+ GstStructure *s;
+ gchar *description;
+
+ g_return_val_if_fail (element != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+ g_return_val_if_fail (protocol != NULL, FALSE);
+
+ description = gst_base_utils_get_sink_description (protocol);
+
+ s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
+ "urisink", "detail", G_TYPE_STRING, protocol, "name", G_TYPE_STRING,
+ description, NULL);
+
+ g_free (description);
+ return gst_message_new_element (GST_OBJECT_CAST (element), s);
+}
+
+/**
+ * gst_missing_element_message_new:
+ * @element: the #GstElement posting the message
+ * @factory_name: the name of the missing element (element factory),
+ * e.g. "videoscale" or "cdparanoiasrc"
+ *
+ * Creates a missing-plugin message for @element to notify the application
+ * that a certain required element is missing. This function is mainly for
+ * use in plugins.
+ *
+ * Returns: a new #GstMessage, or NULL on error
+ */
+GstMessage *
+gst_missing_element_message_new (GstElement * element,
+ const gchar * factory_name)
+{
+ GstStructure *s;
+ gchar *description;
+
+ g_return_val_if_fail (element != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+ g_return_val_if_fail (factory_name != NULL, FALSE);
+
+ description = gst_base_utils_get_element_description (factory_name);
+
+ s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
+ "element", "detail", G_TYPE_STRING, factory_name, "name", G_TYPE_STRING,
+ description, NULL);
+
+ g_free (description);
+ return gst_message_new_element (GST_OBJECT_CAST (element), s);
+}
+
+/**
+ * gst_missing_decoder_message_new:
+ * @element: the #GstElement posting the message
+ * @decode_caps: the (fixed) caps for which a decoder element is needed
+ *
+ * Creates a missing-plugin message for @element to notify the application
+ * that a decoder element for a particular set of (fixed) caps is missing.
+ * This function is mainly for use in plugins.
+ *
+ * Returns: a new #GstMessage, or NULL on error
+ */
+GstMessage *
+gst_missing_decoder_message_new (GstElement * element,
+ const GstCaps * decode_caps)
+{
+ GstStructure *s;
+ GstCaps *caps;
+ gchar *description;
+
+ g_return_val_if_fail (element != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+ g_return_val_if_fail (decode_caps != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_CAPS (decode_caps), FALSE);
+ g_return_val_if_fail (!gst_caps_is_any (decode_caps), FALSE);
+ g_return_val_if_fail (!gst_caps_is_empty (decode_caps), FALSE);
+ g_return_val_if_fail (gst_caps_is_fixed (decode_caps), FALSE);
+
+ description = gst_base_utils_get_decoder_description (decode_caps);
+ caps = copy_and_clean_caps (decode_caps);
+
+ s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
+ "decoder", "detail", GST_TYPE_CAPS, caps, "name", G_TYPE_STRING,
+ description, NULL);
+
+ gst_caps_unref (caps);
+ g_free (description);
+
+ return gst_message_new_element (GST_OBJECT_CAST (element), s);
+}
+
+/**
+ * gst_missing_encoder_message_new:
+ * @element: the #GstElement posting the message
+ * @encode_caps: the (fixed) caps for which an encoder element is needed
+ *
+ * Creates a missing-plugin message for @element to notify the application
+ * that an encoder element for a particular set of (fixed) caps is missing.
+ * This function is mainly for use in plugins.
+ *
+ * Returns: a new #GstMessage, or NULL on error
+ */
+GstMessage *
+gst_missing_encoder_message_new (GstElement * element,
+ const GstCaps * encode_caps)
+{
+ GstStructure *s;
+ GstCaps *caps;
+ gchar *description;
+
+ g_return_val_if_fail (element != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+ g_return_val_if_fail (encode_caps != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_CAPS (encode_caps), FALSE);
+ g_return_val_if_fail (!gst_caps_is_any (encode_caps), FALSE);
+ g_return_val_if_fail (!gst_caps_is_empty (encode_caps), FALSE);
+ g_return_val_if_fail (gst_caps_is_fixed (encode_caps), FALSE);
+
+ description = gst_base_utils_get_encoder_description (encode_caps);
+ caps = copy_and_clean_caps (encode_caps);
+
+ s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
+ "encoder", "detail", GST_TYPE_CAPS, caps, "name", G_TYPE_STRING,
+ description, NULL);
+
+ gst_caps_unref (caps);
+ g_free (description);
+
+ return gst_message_new_element (GST_OBJECT_CAST (element), s);
+}
+
+static gboolean
+missing_structure_get_string_detail (const GstStructure * s, gchar ** p_detail)
+{
+ const gchar *detail;
+ GType detail_type;
+
+ *p_detail = NULL;
+
+ detail_type = gst_structure_get_field_type (s, "detail");
+ if (!g_type_is_a (detail_type, G_TYPE_STRING)) {
+ GST_WARNING ("expected 'detail' field to be of G_TYPE_STRING");
+ return FALSE;
+ }
+
+ detail = gst_structure_get_string (s, "detail");
+ if (detail == NULL || *detail == '\0') {
+ GST_WARNING ("empty 'detail' field");
+ return FALSE;
+ }
+ *p_detail = g_strdup (detail);
+ return TRUE;
+}
+
+static gboolean
+missing_structure_get_caps_detail (const GstStructure * s, GstCaps ** p_caps)
+{
+ const GstCaps *caps;
+ const GValue *val;
+ GType detail_type;
+
+ *p_caps = NULL;
+
+ detail_type = gst_structure_get_field_type (s, "detail");
+ if (!g_type_is_a (detail_type, GST_TYPE_CAPS)) {
+ GST_WARNING ("expected 'detail' field to be of GST_TYPE_CAPS");
+ return FALSE;
+ }
+
+ val = gst_structure_get_value (s, "detail");
+ caps = gst_value_get_caps (val);
+ if (gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
+ GST_WARNING ("EMPTY or ANY caps not allowed");
+ return FALSE;
+ }
+
+ *p_caps = gst_caps_copy (caps);
+ return TRUE;
+}
+
+/**
+ * gst_missing_plugin_message_get_installer_detail:
+ * @msg: a missing-plugin #GstMessage of type #GST_MESSAGE_ELEMENT
+ *
+ * Returns an opaque string containing all the details about the missing
+ * element to be passed to an external installer or installer library
+ * such as libgimme-codec.
+ *
+ * This function is mainly for applications that use libgimme-codec or
+ * other libraries that call external plugin installation mechanisms.
+ *
+ * Returns: a newly-allocated detail string, or NULL on error. Free string
+ * with g_free() when not needed any longer.
+ */
+gchar *
+gst_missing_plugin_message_get_installer_detail (GstMessage * msg)
+{
+ GstMissingType missing_type;
+ const gchar *progname;
+ const gchar *type;
+ GString *str = NULL;
+ gchar *detail = NULL;
+ gchar *desc;
+
+ g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
+
+ GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, msg->structure);
+
+ missing_type = missing_structure_get_type (msg->structure);
+ if (missing_type == GST_MISSING_TYPE_UNKNOWN) {
+ GST_WARNING ("couldn't parse 'type' field");
+ goto error;
+ }
+
+ type = gst_structure_get_string (msg->structure, "type");
+ g_assert (type != NULL); /* validity already checked above */
+
+ str = g_string_new (GST_DETAIL_STRING_MARKER "|");
+ g_string_append_printf (str, "%u.%u|", GST_VERSION_MAJOR, GST_VERSION_MINOR);
+
+ progname = (const gchar *) g_get_prgname ();
+ if (progname) {
+ g_string_append_printf (str, "%s|", progname);
+ } else {
+ g_string_append_printf (str, "pid/%lu", (gulong) getpid ());
+ }
+
+ desc = gst_missing_plugin_message_get_description (msg);
+ if (desc) {
+ g_strdelimit (desc, "|", '#');
+ g_string_append_printf (str, "%s|", desc);
+ g_free (desc);
+ } else {
+ g_string_append (str, "|");
+ }
+
+ switch (missing_type) {
+ case GST_MISSING_TYPE_URISOURCE:
+ case GST_MISSING_TYPE_URISINK:
+ case GST_MISSING_TYPE_ELEMENT:
+ if (!missing_structure_get_string_detail (msg->structure, &detail))
+ goto error;
+ break;
+ case GST_MISSING_TYPE_DECODER:
+ case GST_MISSING_TYPE_ENCODER:{
+ GstCaps *caps = NULL;
+
+ if (!missing_structure_get_caps_detail (msg->structure, &caps))
+ goto error;
+
+ detail = gst_caps_to_string (caps);
+ gst_caps_unref (caps);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ g_string_append_printf (str, "%s-%s", type, detail);
+ g_free (detail);
+
+ return g_string_free (str, FALSE);
+
+/* ERRORS */
+error:
+ {
+ GST_WARNING ("Failed to parse missing-plugin msg: %" GST_PTR_FORMAT, msg);
+ if (str)
+ g_string_free (str, TRUE);
+ return NULL;
+ }
+}
+
+/**
+ * gst_missing_plugin_message_get_description:
+ * @msg: a missing-plugin #GstMessage of type #GST_MESSAGE_ELEMENT
+ *
+ * Returns a localised string describing the missing feature, for use in
+ * error dialogs and the like. Should never return NULL unless @msg is not
+ * a valid missing-plugin message.
+ *
+ * This function is mainly for applications that need a human-readable string
+ * describing a missing plugin, given a previously collected missing-plugin
+ * message
+ *
+ * Returns: a newly-allocated description string, or NULL on error. Free
+ * string with g_free() when not needed any longer.
+ */
+gchar *
+gst_missing_plugin_message_get_description (GstMessage * msg)
+{
+ GstMissingType missing_type;
+ const gchar *desc;
+ gchar *ret = NULL;
+
+ g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
+
+ GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, msg->structure);
+
+ desc = gst_structure_get_string (msg->structure, "name");
+ if (desc != NULL && *desc != '\0') {
+ ret = g_strdup (desc);
+ goto done;
+ }
+
+ /* fallback #1 */
+ missing_type = missing_structure_get_type (msg->structure);
+
+ switch (missing_type) {
+ case GST_MISSING_TYPE_URISOURCE:
+ case GST_MISSING_TYPE_URISINK:
+ case GST_MISSING_TYPE_ELEMENT:{
+ gchar *detail = NULL;
+
+ if (missing_structure_get_string_detail (msg->structure, &detail)) {
+ if (missing_type == GST_MISSING_TYPE_URISOURCE)
+ ret = gst_base_utils_get_source_description (detail);
+ else if (missing_type == GST_MISSING_TYPE_URISINK)
+ ret = gst_base_utils_get_sink_description (detail);
+ else
+ ret = gst_base_utils_get_sink_description (detail);
+ g_free (detail);
+ }
+ break;
+ }
+ case GST_MISSING_TYPE_DECODER:
+ case GST_MISSING_TYPE_ENCODER:{
+ GstCaps *caps = NULL;
+
+ if (missing_structure_get_caps_detail (msg->structure, &caps)) {
+ if (missing_type == GST_MISSING_TYPE_DECODER)
+ ret = gst_base_utils_get_decoder_description (caps);
+ else
+ ret = gst_base_utils_get_encoder_description (caps);
+ gst_caps_unref (caps);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (ret)
+ goto done;
+
+ /* fallback #2 */
+ switch (missing_type) {
+ case GST_MISSING_TYPE_URISOURCE:
+ desc = _("Unknown source element");
+ break;
+ case GST_MISSING_TYPE_URISINK:
+ desc = _("Unknown sink element");
+ break;
+ case GST_MISSING_TYPE_ELEMENT:
+ desc = _("Unknown element");
+ break;
+ case GST_MISSING_TYPE_DECODER:
+ desc = _("Unknown decoder element");
+ break;
+ case GST_MISSING_TYPE_ENCODER:
+ desc = _("Unknown encoder element");
+ break;
+ default:
+ /* we should really never get here, but we better still return
+ * something if we do */
+ desc = _("Plugin or element of unknown type");
+ break;
+ }
+ ret = g_strdup (desc);
+
+done:
+
+ GST_LOG ("returning '%s'", ret);
+ return ret;
+}
+
+/**
+ * gst_is_missing_plugin_message:
+ * @msg: a #GstMessage
+ *
+ * Checks whether @msg is a missing plugins message.
+ *
+ * Returns: %TRUE if @msg is a missing-plugins message, otherwise %FALSE.
+ */
+gboolean
+gst_is_missing_plugin_message (GstMessage * msg)
+{
+ g_return_val_if_fail (msg != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_MESSAGE (msg), FALSE);
+
+ if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ELEMENT || msg->structure == NULL)
+ return FALSE;
+
+ return gst_structure_has_name (msg->structure, "missing-plugin");
+}
--- /dev/null
+/* GStreamer base utils library missing plugins support
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_BASE_UTILS_MISSING_PLUGINS_H__
+#define __GST_BASE_UTILS_MISSING_PLUGINS_H__
+
+#include <gst/gstmessage.h>
+#include <gst/gstcaps.h>
+
+G_BEGIN_DECLS
+
+/*
+ * functions to create missing-plugin messages, for use by plugins primarily
+ */
+
+GstMessage * gst_missing_uri_source_message_new (GstElement * element,
+ const gchar * protocol);
+
+GstMessage * gst_missing_uri_sink_message_new (GstElement * element,
+ const gchar * protocol);
+
+GstMessage * gst_missing_element_message_new (GstElement * element,
+ const gchar * factory_name);
+
+GstMessage * gst_missing_decoder_message_new (GstElement * element,
+ const GstCaps * decode_caps);
+
+GstMessage * gst_missing_encoder_message_new (GstElement * element,
+ const GstCaps * encode_caps);
+
+/*
+ * functions for use by the application when dealing with missing-plugin messages
+ */
+
+gchar * gst_missing_plugin_message_get_installer_detail (GstMessage * msg);
+
+gchar * gst_missing_plugin_message_get_description (GstMessage * msg);
+
+gboolean gst_is_missing_plugin_message (GstMessage * msg);
+
+G_END_DECLS
+
+#endif /* __GST_BASE_UTILS_MISSING_PLUGINS_H__ */
+
Version: @VERSION@
Requires: gstreamer-@GST_MAJORMINOR@
-Libs: -L${libdir}/audio -L${libdir}/cdda -L${libdir}/floatcast -L${libdir}/interfaces -L${libdir}/netbuffer -L${libdir}/riff -L${libdir}/rtp -L${libdir}/tag -L${libdir}/video
+Libs: -L${libdir}/audio -L${libdir}/cdda -L${libdir}/floatcast -L${libdir}/interfaces -L${libdir}/netbuffer -L${libdir}/riff -L${libdir}/rtp -L${libdir}/tag -L${libdir}/utils -L${libdir}/video
Cflags: -I${includedir}
-libraries=audio cdda floatcast interfaces netbuffer riff tag video
+libraries=audio cdda floatcast interfaces netbuffer riff tag utils video
Libs: -L${libdir}
Cflags: -I${includedir}
-libraries=audio cdda floatcast interfaces netbuffer riff rtp tag video
+libraries=audio cdda floatcast interfaces netbuffer riff rtp tag utils video
libs/cddabasesrc \
libs/tag \
libs/video \
+ libs/utils \
pipelines/simple-launch-lines
# TORTURE_TO_FIX = \
libs_tag_LDADD = \
$(top_builddir)/gst-libs/gst/tag/libgsttag-@GST_MAJORMINOR@.la $(LDADD)
-elements_alsa_CFLAGS = \
+libs_utils_CFLAGS = \
$(GST_PLUGINS_BASE_CFLAGS) \
$(AM_CFLAGS)
+libs_utils_LDADD = \
+ $(top_builddir)/gst-libs/gst/utils/libgstbaseutils-@GST_MAJORMINOR@.la $(LDADD)
+elements_alsa_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(AM_CFLAGS)
elements_alsa_LDADD = \
$(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-@GST_MAJORMINOR@.la \
$(LDADD)
.dirstamp
-cddabasesrc
-video
audio
-tag
+cddabasesrc
netbuffer
+tag
+utils
+video
--- /dev/null
+/* GStreamer unit tests for libgstbaseutils
+ *
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gst/check/gstcheck.h>
+#include <gst/utils/base-utils.h>
+#include <unistd.h>
+
+static void
+missing_msg_check_getters (GstMessage * msg)
+{
+ gchar *str;
+
+ str = gst_missing_plugin_message_get_installer_detail (msg);
+ fail_unless (str != NULL);
+ fail_unless (*str != '\0');
+ fail_unless (g_str_has_prefix (str, "gstreamer.net|"));
+ g_free (str);
+
+ str = gst_missing_plugin_message_get_description (msg);
+ fail_unless (str != NULL);
+ fail_unless (*str != '\0');
+ g_free (str);
+}
+
+GST_START_TEST (test_base_utils_post_missing_messages)
+{
+ GstElement *pipeline;
+ GstStructure *s;
+ GstMessage *msg;
+ GstCaps *caps;
+ GstBus *bus;
+
+ gst_base_utils_init ();
+
+ pipeline = gst_pipeline_new ("pipeline");
+ bus = gst_element_get_bus (pipeline);
+
+ /* first, test common assertion failure cases */
+ ASSERT_CRITICAL (msg = gst_missing_uri_source_message_new (NULL, "http"););
+ ASSERT_CRITICAL (gst_missing_uri_source_message_new (pipeline, NULL));
+
+ ASSERT_CRITICAL (gst_missing_uri_sink_message_new (NULL, "http"));
+ ASSERT_CRITICAL (gst_missing_uri_sink_message_new (pipeline, NULL));
+
+ ASSERT_CRITICAL (gst_missing_element_message_new (NULL, "rgbfyltr"));
+ ASSERT_CRITICAL (gst_missing_element_message_new (pipeline, NULL));
+
+ caps = gst_caps_new_simple ("audio/x-dontexist", NULL);
+
+ ASSERT_CRITICAL (gst_missing_decoder_message_new (NULL, caps));
+ ASSERT_CRITICAL (gst_missing_decoder_message_new (pipeline, NULL));
+
+ ASSERT_CRITICAL (gst_missing_encoder_message_new (NULL, caps));
+ ASSERT_CRITICAL (gst_missing_encoder_message_new (pipeline, NULL));
+
+ gst_caps_unref (caps);
+
+ /* URI source (with existing protocol) */
+ msg = gst_missing_uri_source_message_new (pipeline, "http");
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "urisource");
+ fail_unless (gst_structure_has_field_typed (s, "detail", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "detail"), "http");
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* URI sink (with existing protocol) */
+ msg = gst_missing_uri_sink_message_new (pipeline, "smb");
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "urisink");
+ fail_unless (gst_structure_has_field_typed (s, "detail", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "detail"), "smb");
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* URI source (with bogus protocol) */
+ msg = gst_missing_uri_source_message_new (pipeline, "chchck");
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "urisource");
+ fail_unless (gst_structure_has_field_typed (s, "detail", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "detail"), "chchck");
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* URI sink (with bogus protocol) */
+ msg = gst_missing_uri_sink_message_new (pipeline, "chchck");
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "urisink");
+ fail_unless (gst_structure_has_field_typed (s, "detail", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "detail"), "chchck");
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* element */
+ msg = gst_missing_element_message_new (pipeline, "foobar");
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "element");
+ fail_unless (gst_structure_has_field_typed (s, "detail", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "detail"), "foobar");
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* create bogus caps that don't exist */
+ caps = gst_caps_new_simple ("do/x-not", "exist", G_TYPE_BOOLEAN, FALSE, NULL);
+
+ /* decoder (with unknown caps) */
+ msg = gst_missing_decoder_message_new (pipeline, caps);
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "decoder");
+ fail_unless (gst_structure_has_field_typed (s, "detail", GST_TYPE_CAPS));
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* encoder (with unknown caps) */
+ msg = gst_missing_encoder_message_new (pipeline, caps);
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "encoder");
+ fail_unless (gst_structure_has_field_typed (s, "detail", GST_TYPE_CAPS));
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ gst_caps_unref (caps);
+
+ /* create caps that exist */
+ caps = gst_caps_new_simple ("video/x-matroska", NULL);
+ /* decoder (with known caps) */
+ msg = gst_missing_decoder_message_new (pipeline, caps);
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "decoder");
+ fail_unless (gst_structure_has_field_typed (s, "detail", GST_TYPE_CAPS));
+ fail_unless (gst_structure_has_field_typed (s, "name", G_TYPE_STRING));
+ fail_unless (gst_structure_get_string (s, "name") != NULL);
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* encoder (with known caps) */
+ msg = gst_missing_encoder_message_new (pipeline, caps);
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "encoder");
+ fail_unless (gst_structure_has_field_typed (s, "detail", GST_TYPE_CAPS));
+ fail_unless (gst_structure_has_field_typed (s, "name", G_TYPE_STRING));
+ fail_unless (gst_structure_get_string (s, "name") != NULL);
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ gst_caps_unref (caps);
+
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ gst_object_unref (pipeline);
+ gst_object_unref (bus);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_base_utils_init)
+{
+ /* should be fine to call multiple times */
+ gst_base_utils_init ();
+ gst_base_utils_init ();
+ gst_base_utils_init ();
+ gst_base_utils_init ();
+}
+
+GST_END_TEST;
+
+static const gchar *caps_strings[] = {
+ /* formats with static descriptions */
+ "application/ogg", "application/vnd.rn-realmedia", "video/x-fli",
+ "video/x-flv", "video/x-matroska", "video/x-ms-asf", "video/x-msvideo",
+ "video/x-quicktime", "video/quicktime", "audio/x-ac3", "audio/ac3",
+ "audio/x-private-ac3", "audio/x-private1-ac3", "audio/x-adpcm",
+ "audio/aiff", "audio/x-alaw", "audio/amr", "audio/AMR", "audio/AMR-WB",
+ "audio/iLBC-sh", "audio/ms-gsm", "audio/qcelp", "audio/x-adpcm",
+ "audio/x-aiff", "audio/x-alac", "audio/x-amr-nb-sh", "audio/x-amr-wb-sh",
+ "audio/x-au", "audio/x-cinepak", "audio/x-dpcm", "audio/x-dts",
+ "audio/x-dv", "audio/x-flac", "audio/x-gsm", "audio/x-iec958",
+ "audio/x-iLBC", "audio/x-ircam", "audio/x-lpcm", "audio/x-private1-lpcm",
+ "audio/x-m4a", "audio/x-mod", "audio/x-mulaw", "audio/x-musepack",
+ "audio/x-nist", "audio/x-nsf", "audio/x-paris", "audio/x-qdm2",
+ "audio/x-ralf-mpeg4-generic", "audio/x-sds", "audio/x-shorten",
+ "audio/x-sid", "audio/x-sipro", "audio/x-spc", "audio/x-speex",
+ "audio/x-svx", "audio/x-tta", "audio/x-ttafile",
+ "audio/x-vnd.sony.atrac3", "audio/x-vorbis", "audio/x-voc", "audio/x-w64",
+ "audio/x-wav", "audio/x-wavpack", "audio/x-wavpack-correction",
+ "audio/x-wms", "audio/x-voxware", "video/sp5x", "video/vivo",
+ "video/x-3ivx", "video/x-4xm", "video/x-apple-video", "video/x-camtasia",
+ "video/x-cdxa", "video/x-cinepak", "video/x-cirrus-logic-accupak",
+ "video/x-compressed-yuv", "video/x-dirac", "video/x-dvd-subpicture",
+ "video/x-ffv", "video/x-flash-screen", "video/x-flash-video",
+ "video/x-h261", "video/x-huffyuv", "video/x-intel-h263", "video/x-jpeg",
+ "video/x-mjpeg", "video/x-mjpeg-b", "video/mpegts", "video/x-mng",
+ "video/x-mszh", "video/x-msvideocodec", "video/x-mve", "video/x-nut",
+ "video/x-nuv", "video/x-qdrw", "video/x-raw-gray", "video/x-smc",
+ "video/x-smoke", "video/x-tarkin", "video/x-theora", "video/x-rle",
+ "video/x-ultimotion", "video/x-vcd", "video/x-vmnc", "video/x-vp3",
+ "video/x-vp5", "video/x-vp6", "video/x-vp6-flash", "video/x-vp7",
+ "video/x-xvid", "video/x-zlib", "image/bmp", "image/x-bmp",
+ "image/x-MS-bmp", "image/gif", "image/jpeg", "image/jng", "image/png",
+ "image/pbm", "image/ppm", "image/svg+xml", "image/tiff",
+ "image/x-cmu-raster", "image/x-icon", "image/x-xcf", "image/x-pixmap",
+ "image/x-xpixmap", "image/x-quicktime", "image/x-sun-raster",
+ "image/x-tga", "video/x-dv", "video/x-dv",
+ /* some RTP formats */
+ "application/x-rtp, media=(string)video, encoding-name=(string)TimVCodec",
+ "application/x-rtp, media=(string)audio, encoding-name=(string)TimACodec",
+ "application/x-rtp, media=(string)application, encoding-name=(string)TimMux",
+ "application/x-rtp, media=(string)woohoo, encoding-name=(string)TPM",
+ /* incomplete RTP formats */
+ "application/x-rtp, media=(string)woohoo",
+ "application/x-rtp, encoding-name=(string)TPM",
+ "application/x-rtp, media=(string)woohoo",
+ /* formats with dynamic descriptions */
+ "audio/mpeg, mpegversion=(int)4",
+ "audio/mpeg, mpegversion=(int)1, layer=(int)1",
+ "audio/mpeg, mpegversion=(int)1, layer=(int)2",
+ "audio/mpeg, mpegversion=(int)1, layer=(int)3",
+ "audio/mpeg, mpegversion=(int)1, layer=(int)99",
+ "audio/mpeg, mpegversion=(int)99",
+ "video/mpeg, mpegversion=(int)2, systemstream=(boolean)TRUE",
+ "video/mpeg, systemstream=(boolean)FALSE",
+ "video/mpeg, mpegversion=(int)2",
+ "video/mpeg, mpegversion=(int)1, systemstream=(boolean)FALSE",
+ "video/mpeg, mpegversion=(int)2, systemstream=(boolean)FALSE",
+ "video/mpeg, mpegversion=(int)4, systemstream=(boolean)FALSE",
+ "video/mpeg, mpegversion=(int)99, systemstream=(boolean)TRUE",
+ "video/mpeg, mpegversion=(int)99, systemstream=(boolean)FALSE",
+ "video/mpeg",
+ "video/x-indeo, indeoversion=(int)3",
+ "video/x-indeo, indeoversion=(int)5",
+ "video/x-indeo",
+ "video/x-wmv, wmvversion=(int)1",
+ "video/x-wmv, wmvversion=(int)2",
+ "video/x-wmv, wmvversion=(int)3",
+ "video/x-wmv, wmvversion=(int)99",
+ "video/x-wmv",
+ "audio/x-wma, wmaversion=(int)1",
+ "audio/x-wma, wmaversion=(int)2",
+ "audio/x-wma, wmaversion=(int)3",
+ "audio/x-wma, wmaversion=(int)99",
+ "audio/x-wma",
+ "video/x-divx, divxversion=(int)3",
+ "video/x-divx, divxversion=(int)4",
+ "video/x-divx, divxversion=(int)5",
+ "video/x-divx, divxversion=(int)99",
+ "video/x-divx",
+ "video/x-svq, svqversion=(int)1",
+ "video/x-svq, svqversion=(int)3",
+ "video/x-svq, svqversion=(int)99",
+ "video/x-svq",
+ "video/x-h264, variant=(string)itu",
+ "video/x-h264, variant=(string)videosoft",
+ "video/x-h264, variant=(string)foobar",
+ "video/x-h264",
+ "video/x-h263, variant=(string)itu",
+ "video/x-h263, variant=(string)lead",
+ "video/x-h263, variant=(string)microsoft",
+ "video/x-h263, variant=(string)vdolive",
+ "video/x-h263, variant=(string)vivo",
+ "video/x-h263, variant=(string)xirlink",
+ "video/x-h263, variant=(string)foobar",
+ "video/x-h263",
+ "video/x-msmpeg, msmpegversion=(int)41",
+ "video/x-msmpeg, msmpegversion=(int)42",
+ "video/x-msmpeg, msmpegversion=(int)43",
+ "video/x-msmpeg, msmpegversion=(int)99",
+ "video/x-msmpeg",
+ "video/x-pn-realvideo, rmversion=(int)1",
+ "video/x-pn-realvideo, rmversion=(int)2",
+ "video/x-pn-realvideo, rmversion=(int)3",
+ "video/x-pn-realvideo, rmversion=(int)4",
+ "video/x-pn-realvideo, rmversion=(int)99",
+ "video/x-pn-realvideo",
+ "audio/x-pn-realaudio, raversion=(int)1",
+ "audio/x-pn-realaudio, raversion=(int)2",
+ "audio/x-pn-realaudio, raversion=(int)99",
+ "audio/x-pn-realaudio",
+ "audio/x-mace, maceversion=(int)3",
+ "audio/x-mace, maceversion=(int)6",
+ "audio/x-mace, maceversion=(int)99",
+ "audio/x-mace",
+ "video/x-truemotion, trueversion=(int)1",
+ "video/x-truemotion, trueversion=(int)2",
+ "video/x-truemotion, trueversion=(int)99",
+ "video/x-truemotion",
+ "video/x-asus, asusversion=(int)1",
+ "video/x-asus, asusversion=(int)2",
+ "video/x-asus, asusversion=(int)99",
+ "video/x-asus",
+ "video/x-xan, wcversion=(int)1",
+ "video/x-xan, wcversion=(int)99",
+ "video/x-xan",
+ "video/x-ati-vcr, vcrversion=(int)1",
+ "video/x-ati-vcr, vcrversion=(int)2",
+ "video/x-ati-vcr, vcrversion=(int)99",
+ "video/x-ati-vcr",
+ /* raw audio */
+ "audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int)16, depth=(int)16, rate=(int)44100, channels=(int)2",
+ "audio/x-raw-float, rate=(int)22050, channels=(int)2, endianness=(int)1234, width=(int)32",
+ /* raw video */
+ "video/x-raw-rgb, bpp=(int)16, endianness=(int)1234, depth=(int)16, red_mask=(int)63488, green_mask=(int)2016, blue_mask=(int)31, width=(int)320, height=(int)240, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)1/1",
+ "video/x-raw-yuv, format=(fourcc)YUY2, width=(int)320, height=(int)240, framerate=(fraction)30/1",
+ /* and a made-up format */
+ "video/x-tpm"
+};
+
+GST_START_TEST (test_base_utils_get_codec_description)
+{
+ gint i;
+
+ gst_base_utils_init ();
+
+ for (i = 0; i < G_N_ELEMENTS (caps_strings); ++i) {
+ GstCaps *caps;
+ gchar *desc;
+
+ caps = gst_caps_from_string (caps_strings[i]);
+ fail_unless (caps != NULL, "could not create caps from string '%s'",
+ caps_strings[i]);
+ GST_LOG ("Caps %s:", caps_strings[i]);
+ desc = gst_base_utils_get_codec_description (caps);
+ fail_unless (desc != NULL);
+ GST_LOG (" - codec : %s", desc);
+ g_free (desc);
+ desc = gst_base_utils_get_decoder_description (caps);
+ fail_unless (desc != NULL);
+ GST_LOG (" - decoder : %s", desc);
+ g_free (desc);
+ desc = gst_base_utils_get_encoder_description (caps);
+ fail_unless (desc != NULL);
+ GST_LOG (" - encoder : %s", desc);
+ g_free (desc);
+ gst_caps_unref (caps);
+ }
+}
+
+GST_END_TEST;
+GST_START_TEST (test_base_utils_taglist_add_codec_info)
+{
+ GstTagList *list;
+ GstCaps *caps;
+
+ gst_base_utils_init ();
+ list = gst_tag_list_new ();
+ caps = gst_caps_new_simple ("video/x-theora", NULL);
+ ASSERT_CRITICAL (fail_if
+ (gst_base_utils_add_codec_description_to_tag_list (NULL,
+ GST_TAG_VIDEO_CODEC, caps)));
+ ASSERT_CRITICAL (fail_if
+ (gst_base_utils_add_codec_description_to_tag_list (list, NULL, caps)));
+ ASSERT_CRITICAL (fail_if
+ (gst_base_utils_add_codec_description_to_tag_list (list, "asdfa", caps)));
+ ASSERT_CRITICAL (fail_if
+ (gst_base_utils_add_codec_description_to_tag_list (list,
+ GST_TAG_IMAGE, caps)));
+ ASSERT_CRITICAL (fail_if
+ (gst_base_utils_add_codec_description_to_tag_list (list,
+ GST_TAG_VIDEO_CODEC, NULL)));
+ /* FIXME: do something here */
+ fail_unless (gst_base_utils_add_codec_description_to_tag_list (list,
+ GST_TAG_VIDEO_CODEC, caps));
+ fail_if (gst_tag_list_is_empty (list));
+ gst_tag_list_free (list);
+ gst_caps_unref (caps);
+}
+
+GST_END_TEST;
+static Suite *
+libgstbaseutils_suite (void)
+{
+ Suite *s = suite_create ("base utils library");
+ TCase *tc_chain = tcase_create ("general");
+
+ suite_add_tcase (s, tc_chain);
+ tcase_add_test (tc_chain, test_base_utils_init);
+ tcase_add_test (tc_chain, test_base_utils_post_missing_messages);
+ tcase_add_test (tc_chain, test_base_utils_taglist_add_codec_info);
+ tcase_add_test (tc_chain, test_base_utils_get_codec_description);
+ return s;
+}
+
+GST_CHECK_MAIN (libgstbaseutils);
--- /dev/null
+/* GStreamer unit tests for libgstbaseutils
+ *
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gst/check/gstcheck.h>
+#include <gst/utils/base-utils.h>
+#include <unistd.h>
+
+static void
+missing_msg_check_getters (GstMessage * msg)
+{
+ gchar *str;
+
+ str = gst_missing_plugin_message_get_installer_detail (msg);
+ fail_unless (str != NULL);
+ fail_unless (*str != '\0');
+ fail_unless (g_str_has_prefix (str, "gstreamer.net|"));
+ g_free (str);
+
+ str = gst_missing_plugin_message_get_description (msg);
+ fail_unless (str != NULL);
+ fail_unless (*str != '\0');
+ g_free (str);
+}
+
+GST_START_TEST (test_base_utils_post_missing_messages)
+{
+ GstElement *pipeline;
+ GstStructure *s;
+ GstMessage *msg;
+ GstCaps *caps;
+ GstBus *bus;
+
+ gst_base_utils_init ();
+
+ pipeline = gst_pipeline_new ("pipeline");
+ bus = gst_element_get_bus (pipeline);
+
+ /* first, test common assertion failure cases */
+ ASSERT_CRITICAL (msg = gst_missing_uri_source_message_new (NULL, "http"););
+ ASSERT_CRITICAL (gst_missing_uri_source_message_new (pipeline, NULL));
+
+ ASSERT_CRITICAL (gst_missing_uri_sink_message_new (NULL, "http"));
+ ASSERT_CRITICAL (gst_missing_uri_sink_message_new (pipeline, NULL));
+
+ ASSERT_CRITICAL (gst_missing_element_message_new (NULL, "rgbfyltr"));
+ ASSERT_CRITICAL (gst_missing_element_message_new (pipeline, NULL));
+
+ caps = gst_caps_new_simple ("audio/x-dontexist", NULL);
+
+ ASSERT_CRITICAL (gst_missing_decoder_message_new (NULL, caps));
+ ASSERT_CRITICAL (gst_missing_decoder_message_new (pipeline, NULL));
+
+ ASSERT_CRITICAL (gst_missing_encoder_message_new (NULL, caps));
+ ASSERT_CRITICAL (gst_missing_encoder_message_new (pipeline, NULL));
+
+ gst_caps_unref (caps);
+
+ /* URI source (with existing protocol) */
+ msg = gst_missing_uri_source_message_new (pipeline, "http");
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "urisource");
+ fail_unless (gst_structure_has_field_typed (s, "detail", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "detail"), "http");
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* URI sink (with existing protocol) */
+ msg = gst_missing_uri_sink_message_new (pipeline, "smb");
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "urisink");
+ fail_unless (gst_structure_has_field_typed (s, "detail", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "detail"), "smb");
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* URI source (with bogus protocol) */
+ msg = gst_missing_uri_source_message_new (pipeline, "chchck");
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "urisource");
+ fail_unless (gst_structure_has_field_typed (s, "detail", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "detail"), "chchck");
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* URI sink (with bogus protocol) */
+ msg = gst_missing_uri_sink_message_new (pipeline, "chchck");
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "urisink");
+ fail_unless (gst_structure_has_field_typed (s, "detail", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "detail"), "chchck");
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* element */
+ msg = gst_missing_element_message_new (pipeline, "foobar");
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "element");
+ fail_unless (gst_structure_has_field_typed (s, "detail", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "detail"), "foobar");
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* create bogus caps that don't exist */
+ caps = gst_caps_new_simple ("do/x-not", "exist", G_TYPE_BOOLEAN, FALSE, NULL);
+
+ /* decoder (with unknown caps) */
+ msg = gst_missing_decoder_message_new (pipeline, caps);
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "decoder");
+ fail_unless (gst_structure_has_field_typed (s, "detail", GST_TYPE_CAPS));
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* encoder (with unknown caps) */
+ msg = gst_missing_encoder_message_new (pipeline, caps);
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "encoder");
+ fail_unless (gst_structure_has_field_typed (s, "detail", GST_TYPE_CAPS));
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ gst_caps_unref (caps);
+
+ /* create caps that exist */
+ caps = gst_caps_new_simple ("video/x-matroska", NULL);
+ /* decoder (with known caps) */
+ msg = gst_missing_decoder_message_new (pipeline, caps);
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "decoder");
+ fail_unless (gst_structure_has_field_typed (s, "detail", GST_TYPE_CAPS));
+ fail_unless (gst_structure_has_field_typed (s, "name", G_TYPE_STRING));
+ fail_unless (gst_structure_get_string (s, "name") != NULL);
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ /* encoder (with known caps) */
+ msg = gst_missing_encoder_message_new (pipeline, caps);
+ fail_unless (msg != NULL);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "encoder");
+ fail_unless (gst_structure_has_field_typed (s, "detail", GST_TYPE_CAPS));
+ fail_unless (gst_structure_has_field_typed (s, "name", G_TYPE_STRING));
+ fail_unless (gst_structure_get_string (s, "name") != NULL);
+ missing_msg_check_getters (msg);
+ gst_message_unref (msg);
+
+ gst_caps_unref (caps);
+
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ gst_object_unref (pipeline);
+ gst_object_unref (bus);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_base_utils_init)
+{
+ /* should be fine to call multiple times */
+ gst_base_utils_init ();
+ gst_base_utils_init ();
+ gst_base_utils_init ();
+ gst_base_utils_init ();
+}
+
+GST_END_TEST;
+
+static const gchar *caps_strings[] = {
+ /* formats with static descriptions */
+ "application/ogg", "application/vnd.rn-realmedia", "video/x-fli",
+ "video/x-flv", "video/x-matroska", "video/x-ms-asf", "video/x-msvideo",
+ "video/x-quicktime", "video/quicktime", "audio/x-ac3", "audio/ac3",
+ "audio/x-private-ac3", "audio/x-private1-ac3", "audio/x-adpcm",
+ "audio/aiff", "audio/x-alaw", "audio/amr", "audio/AMR", "audio/AMR-WB",
+ "audio/iLBC-sh", "audio/ms-gsm", "audio/qcelp", "audio/x-adpcm",
+ "audio/x-aiff", "audio/x-alac", "audio/x-amr-nb-sh", "audio/x-amr-wb-sh",
+ "audio/x-au", "audio/x-cinepak", "audio/x-dpcm", "audio/x-dts",
+ "audio/x-dv", "audio/x-flac", "audio/x-gsm", "audio/x-iec958",
+ "audio/x-iLBC", "audio/x-ircam", "audio/x-lpcm", "audio/x-private1-lpcm",
+ "audio/x-m4a", "audio/x-mod", "audio/x-mulaw", "audio/x-musepack",
+ "audio/x-nist", "audio/x-nsf", "audio/x-paris", "audio/x-qdm2",
+ "audio/x-ralf-mpeg4-generic", "audio/x-sds", "audio/x-shorten",
+ "audio/x-sid", "audio/x-sipro", "audio/x-spc", "audio/x-speex",
+ "audio/x-svx", "audio/x-tta", "audio/x-ttafile",
+ "audio/x-vnd.sony.atrac3", "audio/x-vorbis", "audio/x-voc", "audio/x-w64",
+ "audio/x-wav", "audio/x-wavpack", "audio/x-wavpack-correction",
+ "audio/x-wms", "audio/x-voxware", "video/sp5x", "video/vivo",
+ "video/x-3ivx", "video/x-4xm", "video/x-apple-video", "video/x-camtasia",
+ "video/x-cdxa", "video/x-cinepak", "video/x-cirrus-logic-accupak",
+ "video/x-compressed-yuv", "video/x-dirac", "video/x-dvd-subpicture",
+ "video/x-ffv", "video/x-flash-screen", "video/x-flash-video",
+ "video/x-h261", "video/x-huffyuv", "video/x-intel-h263", "video/x-jpeg",
+ "video/x-mjpeg", "video/x-mjpeg-b", "video/mpegts", "video/x-mng",
+ "video/x-mszh", "video/x-msvideocodec", "video/x-mve", "video/x-nut",
+ "video/x-nuv", "video/x-qdrw", "video/x-raw-gray", "video/x-smc",
+ "video/x-smoke", "video/x-tarkin", "video/x-theora", "video/x-rle",
+ "video/x-ultimotion", "video/x-vcd", "video/x-vmnc", "video/x-vp3",
+ "video/x-vp5", "video/x-vp6", "video/x-vp6-flash", "video/x-vp7",
+ "video/x-xvid", "video/x-zlib", "image/bmp", "image/x-bmp",
+ "image/x-MS-bmp", "image/gif", "image/jpeg", "image/jng", "image/png",
+ "image/pbm", "image/ppm", "image/svg+xml", "image/tiff",
+ "image/x-cmu-raster", "image/x-icon", "image/x-xcf", "image/x-pixmap",
+ "image/x-xpixmap", "image/x-quicktime", "image/x-sun-raster",
+ "image/x-tga", "video/x-dv", "video/x-dv",
+ /* some RTP formats */
+ "application/x-rtp, media=(string)video, encoding-name=(string)TimVCodec",
+ "application/x-rtp, media=(string)audio, encoding-name=(string)TimACodec",
+ "application/x-rtp, media=(string)application, encoding-name=(string)TimMux",
+ "application/x-rtp, media=(string)woohoo, encoding-name=(string)TPM",
+ /* incomplete RTP formats */
+ "application/x-rtp, media=(string)woohoo",
+ "application/x-rtp, encoding-name=(string)TPM",
+ "application/x-rtp, media=(string)woohoo",
+ /* formats with dynamic descriptions */
+ "audio/mpeg, mpegversion=(int)4",
+ "audio/mpeg, mpegversion=(int)1, layer=(int)1",
+ "audio/mpeg, mpegversion=(int)1, layer=(int)2",
+ "audio/mpeg, mpegversion=(int)1, layer=(int)3",
+ "audio/mpeg, mpegversion=(int)1, layer=(int)99",
+ "audio/mpeg, mpegversion=(int)99",
+ "video/mpeg, mpegversion=(int)2, systemstream=(boolean)TRUE",
+ "video/mpeg, systemstream=(boolean)FALSE",
+ "video/mpeg, mpegversion=(int)2",
+ "video/mpeg, mpegversion=(int)1, systemstream=(boolean)FALSE",
+ "video/mpeg, mpegversion=(int)2, systemstream=(boolean)FALSE",
+ "video/mpeg, mpegversion=(int)4, systemstream=(boolean)FALSE",
+ "video/mpeg, mpegversion=(int)99, systemstream=(boolean)TRUE",
+ "video/mpeg, mpegversion=(int)99, systemstream=(boolean)FALSE",
+ "video/mpeg",
+ "video/x-indeo, indeoversion=(int)3",
+ "video/x-indeo, indeoversion=(int)5",
+ "video/x-indeo",
+ "video/x-wmv, wmvversion=(int)1",
+ "video/x-wmv, wmvversion=(int)2",
+ "video/x-wmv, wmvversion=(int)3",
+ "video/x-wmv, wmvversion=(int)99",
+ "video/x-wmv",
+ "audio/x-wma, wmaversion=(int)1",
+ "audio/x-wma, wmaversion=(int)2",
+ "audio/x-wma, wmaversion=(int)3",
+ "audio/x-wma, wmaversion=(int)99",
+ "audio/x-wma",
+ "video/x-divx, divxversion=(int)3",
+ "video/x-divx, divxversion=(int)4",
+ "video/x-divx, divxversion=(int)5",
+ "video/x-divx, divxversion=(int)99",
+ "video/x-divx",
+ "video/x-svq, svqversion=(int)1",
+ "video/x-svq, svqversion=(int)3",
+ "video/x-svq, svqversion=(int)99",
+ "video/x-svq",
+ "video/x-h264, variant=(string)itu",
+ "video/x-h264, variant=(string)videosoft",
+ "video/x-h264, variant=(string)foobar",
+ "video/x-h264",
+ "video/x-h263, variant=(string)itu",
+ "video/x-h263, variant=(string)lead",
+ "video/x-h263, variant=(string)microsoft",
+ "video/x-h263, variant=(string)vdolive",
+ "video/x-h263, variant=(string)vivo",
+ "video/x-h263, variant=(string)xirlink",
+ "video/x-h263, variant=(string)foobar",
+ "video/x-h263",
+ "video/x-msmpeg, msmpegversion=(int)41",
+ "video/x-msmpeg, msmpegversion=(int)42",
+ "video/x-msmpeg, msmpegversion=(int)43",
+ "video/x-msmpeg, msmpegversion=(int)99",
+ "video/x-msmpeg",
+ "video/x-pn-realvideo, rmversion=(int)1",
+ "video/x-pn-realvideo, rmversion=(int)2",
+ "video/x-pn-realvideo, rmversion=(int)3",
+ "video/x-pn-realvideo, rmversion=(int)4",
+ "video/x-pn-realvideo, rmversion=(int)99",
+ "video/x-pn-realvideo",
+ "audio/x-pn-realaudio, raversion=(int)1",
+ "audio/x-pn-realaudio, raversion=(int)2",
+ "audio/x-pn-realaudio, raversion=(int)99",
+ "audio/x-pn-realaudio",
+ "audio/x-mace, maceversion=(int)3",
+ "audio/x-mace, maceversion=(int)6",
+ "audio/x-mace, maceversion=(int)99",
+ "audio/x-mace",
+ "video/x-truemotion, trueversion=(int)1",
+ "video/x-truemotion, trueversion=(int)2",
+ "video/x-truemotion, trueversion=(int)99",
+ "video/x-truemotion",
+ "video/x-asus, asusversion=(int)1",
+ "video/x-asus, asusversion=(int)2",
+ "video/x-asus, asusversion=(int)99",
+ "video/x-asus",
+ "video/x-xan, wcversion=(int)1",
+ "video/x-xan, wcversion=(int)99",
+ "video/x-xan",
+ "video/x-ati-vcr, vcrversion=(int)1",
+ "video/x-ati-vcr, vcrversion=(int)2",
+ "video/x-ati-vcr, vcrversion=(int)99",
+ "video/x-ati-vcr",
+ /* raw audio */
+ "audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int)16, depth=(int)16, rate=(int)44100, channels=(int)2",
+ "audio/x-raw-float, rate=(int)22050, channels=(int)2, endianness=(int)1234, width=(int)32",
+ /* raw video */
+ "video/x-raw-rgb, bpp=(int)16, endianness=(int)1234, depth=(int)16, red_mask=(int)63488, green_mask=(int)2016, blue_mask=(int)31, width=(int)320, height=(int)240, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)1/1",
+ "video/x-raw-yuv, format=(fourcc)YUY2, width=(int)320, height=(int)240, framerate=(fraction)30/1",
+ /* and a made-up format */
+ "video/x-tpm"
+};
+
+GST_START_TEST (test_base_utils_get_codec_description)
+{
+ gint i;
+
+ gst_base_utils_init ();
+
+ for (i = 0; i < G_N_ELEMENTS (caps_strings); ++i) {
+ GstCaps *caps;
+ gchar *desc;
+
+ caps = gst_caps_from_string (caps_strings[i]);
+ fail_unless (caps != NULL, "could not create caps from string '%s'",
+ caps_strings[i]);
+ GST_LOG ("Caps %s:", caps_strings[i]);
+ desc = gst_base_utils_get_codec_description (caps);
+ fail_unless (desc != NULL);
+ GST_LOG (" - codec : %s", desc);
+ g_free (desc);
+ desc = gst_base_utils_get_decoder_description (caps);
+ fail_unless (desc != NULL);
+ GST_LOG (" - decoder : %s", desc);
+ g_free (desc);
+ desc = gst_base_utils_get_encoder_description (caps);
+ fail_unless (desc != NULL);
+ GST_LOG (" - encoder : %s", desc);
+ g_free (desc);
+ gst_caps_unref (caps);
+ }
+}
+
+GST_END_TEST;
+GST_START_TEST (test_base_utils_taglist_add_codec_info)
+{
+ GstTagList *list;
+ GstCaps *caps;
+
+ gst_base_utils_init ();
+ list = gst_tag_list_new ();
+ caps = gst_caps_new_simple ("video/x-theora", NULL);
+ ASSERT_CRITICAL (fail_if
+ (gst_base_utils_add_codec_description_to_tag_list (NULL,
+ GST_TAG_VIDEO_CODEC, caps)));
+ ASSERT_CRITICAL (fail_if
+ (gst_base_utils_add_codec_description_to_tag_list (list, NULL, caps)));
+ ASSERT_CRITICAL (fail_if
+ (gst_base_utils_add_codec_description_to_tag_list (list, "asdfa", caps)));
+ ASSERT_CRITICAL (fail_if
+ (gst_base_utils_add_codec_description_to_tag_list (list,
+ GST_TAG_IMAGE, caps)));
+ ASSERT_CRITICAL (fail_if
+ (gst_base_utils_add_codec_description_to_tag_list (list,
+ GST_TAG_VIDEO_CODEC, NULL)));
+ /* FIXME: do something here */
+ fail_unless (gst_base_utils_add_codec_description_to_tag_list (list,
+ GST_TAG_VIDEO_CODEC, caps));
+ fail_if (gst_tag_list_is_empty (list));
+ gst_tag_list_free (list);
+ gst_caps_unref (caps);
+}
+
+GST_END_TEST;
+static Suite *
+libgstbaseutils_suite (void)
+{
+ Suite *s = suite_create ("base utils library");
+ TCase *tc_chain = tcase_create ("general");
+
+ suite_add_tcase (s, tc_chain);
+ tcase_add_test (tc_chain, test_base_utils_init);
+ tcase_add_test (tc_chain, test_base_utils_post_missing_messages);
+ tcase_add_test (tc_chain, test_base_utils_taglist_add_codec_info);
+ tcase_add_test (tc_chain, test_base_utils_get_codec_description);
+ return s;
+}
+
+GST_CHECK_MAIN (libgstbaseutils);