From 1450f0fb189703d888005057de7e58bf888ea9ed Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 9 Jan 2007 14:20:08 +0000 Subject: [PATCH] API: add new libgstbaseutils library with functions Original commit message from CVS: * 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. --- ChangeLog | 49 ++ configure.ac | 4 + docs/libs/gst-plugins-base-libs-docs.sgml | 17 + docs/libs/gst-plugins-base-libs-sections.txt | 37 + gst-libs/gst/Makefile.am | 1 + gst-libs/gst/pbutils/Makefile.am | 19 + gst-libs/gst/pbutils/descriptions.c | 898 +++++++++++++++++++++ gst-libs/gst/pbutils/descriptions.h | 58 ++ gst-libs/gst/pbutils/missing-plugins.c | 545 +++++++++++++ gst-libs/gst/pbutils/missing-plugins.h | 60 ++ gst-libs/gst/pbutils/pbutils.c | 51 ++ gst-libs/gst/pbutils/pbutils.h | 35 + gst-libs/gst/utils/Makefile.am | 19 + gst-libs/gst/utils/base-utils.c | 51 ++ gst-libs/gst/utils/base-utils.h | 35 + gst-libs/gst/utils/descriptions.c | 898 +++++++++++++++++++++ gst-libs/gst/utils/descriptions.h | 58 ++ gst-libs/gst/utils/missing-plugins.c | 545 +++++++++++++ gst-libs/gst/utils/missing-plugins.h | 60 ++ pkgconfig/gstreamer-plugins-base-uninstalled.pc.in | 4 +- pkgconfig/gstreamer-plugins-base.pc.in | 2 +- tests/check/Makefile.am | 8 +- tests/check/libs/.gitignore | 7 +- tests/check/libs/pbutils.c | 447 ++++++++++ tests/check/libs/utils.c | 447 ++++++++++ 25 files changed, 4348 insertions(+), 7 deletions(-) create mode 100644 gst-libs/gst/pbutils/Makefile.am create mode 100644 gst-libs/gst/pbutils/descriptions.c create mode 100644 gst-libs/gst/pbutils/descriptions.h create mode 100644 gst-libs/gst/pbutils/missing-plugins.c create mode 100644 gst-libs/gst/pbutils/missing-plugins.h create mode 100644 gst-libs/gst/pbutils/pbutils.c create mode 100644 gst-libs/gst/pbutils/pbutils.h create mode 100644 gst-libs/gst/utils/Makefile.am create mode 100644 gst-libs/gst/utils/base-utils.c create mode 100644 gst-libs/gst/utils/base-utils.h create mode 100644 gst-libs/gst/utils/descriptions.c create mode 100644 gst-libs/gst/utils/descriptions.h create mode 100644 gst-libs/gst/utils/missing-plugins.c create mode 100644 gst-libs/gst/utils/missing-plugins.h create mode 100644 tests/check/libs/pbutils.c create mode 100644 tests/check/libs/utils.c diff --git a/ChangeLog b/ChangeLog index 10245d3..409c77d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,54 @@ 2007-01-09 Tim-Philipp Müller + * 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 + * ext/ogg/Makefile.am: Dist gstoggdemux.h to fix 'make distcheck'. diff --git a/configure.ac b/configure.ac index d9aa795..5ddd0a7 100644 --- a/configure.ac +++ b/configure.ac @@ -182,6 +182,9 @@ AC_CHECK_HEADERS([sys/socket.h], 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 @@ -619,6 +622,7 @@ gst-libs/gst/netbuffer/Makefile 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 diff --git a/docs/libs/gst-plugins-base-libs-docs.sgml b/docs/libs/gst-plugins-base-libs-docs.sgml index 4bec23a..79ff2e2 100644 --- a/docs/libs/gst-plugins-base-libs-docs.sgml +++ b/docs/libs/gst-plugins-base-libs-docs.sgml @@ -45,6 +45,10 @@ + + + + @@ -173,6 +177,19 @@ &GstTagID3; + + Base Utils Library + + This library should be linked to by getting cflags and libs from + gstreamer-plugins-base.pc and adding + -lgstbaseutils-&GST_MAJORMINOR; to the library + flags. + + &GstBaseUtils; + &GstBaseUtilsDescriptions; + &GstBaseUtilsMissingPlugins; + + Video Library diff --git a/docs/libs/gst-plugins-base-libs-sections.txt b/docs/libs/gst-plugins-base-libs-sections.txt index 4ca4bcb..5bcba8d 100644 --- a/docs/libs/gst-plugins-base-libs-sections.txt +++ b/docs/libs/gst-plugins-base-libs-sections.txt @@ -917,6 +917,43 @@ gst_tag_from_id3_user_tag gst_tag_to_id3_tag +# base utils + +
+gstbaseutils +gst/utils/base-utils.h + +gst_base_utils_init +
+ +
+gstbaseutilsmissingplugins +gst/utils/missing-plugins.h + +gst_missing_plugin_message_get_installer_detail +gst_missing_plugin_message_get_description +gst_is_missing_plugin_message + +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 +
+ +
+gstbaseutilsdescriptions +gst/utils/descriptions.h + +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 +
# video diff --git a/gst-libs/gst/Makefile.am b/gst-libs/gst/Makefile.am index 8ac6dc7..c3a79b6 100644 --- a/gst-libs/gst/Makefile.am +++ b/gst-libs/gst/Makefile.am @@ -11,6 +11,7 @@ SUBDIRS = \ netbuffer \ riff \ rtp \ + utils \ video noinst_HEADERS = gettext.h gst-i18n-plugin.h diff --git a/gst-libs/gst/pbutils/Makefile.am b/gst-libs/gst/pbutils/Makefile.am new file mode 100644 index 0000000..2ba8f6b --- /dev/null +++ b/gst-libs/gst/pbutils/Makefile.am @@ -0,0 +1,19 @@ +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) diff --git a/gst-libs/gst/pbutils/descriptions.c b/gst-libs/gst/pbutils/descriptions.c new file mode 100644 index 0000000..6bcb9a5 --- /dev/null +++ b/gst-libs/gst/pbutils/descriptions.c @@ -0,0 +1,898 @@ +/* GStreamer base utils library source/sink/codec description support + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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 + +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 diff --git a/gst-libs/gst/pbutils/descriptions.h b/gst-libs/gst/pbutils/descriptions.h new file mode 100644 index 0000000..9cba0b8 --- /dev/null +++ b/gst-libs/gst/pbutils/descriptions.h @@ -0,0 +1,58 @@ +/* GStreamer base utils library source/sink/codec description support + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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 +#include + +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__ */ + diff --git a/gst-libs/gst/pbutils/missing-plugins.c b/gst-libs/gst/pbutils/missing-plugins.c new file mode 100644 index 0000000..aa6581a --- /dev/null +++ b/gst-libs/gst/pbutils/missing-plugins.c @@ -0,0 +1,545 @@ +/* GStreamer base utils library missing plugins support + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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 +#endif +#ifdef HAVE_UNISTD_H +# include /* getpid on UNIX */ +#endif +#ifdef HAVE_PROCESS_H +# include /* getpid on win32 */ +#endif + +#include "gst/gst-i18n-plugin.h" + +#include "base-utils.h" + +#include + +#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"); +} diff --git a/gst-libs/gst/pbutils/missing-plugins.h b/gst-libs/gst/pbutils/missing-plugins.h new file mode 100644 index 0000000..25661f2 --- /dev/null +++ b/gst-libs/gst/pbutils/missing-plugins.h @@ -0,0 +1,60 @@ +/* GStreamer base utils library missing plugins support + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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 +#include + +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__ */ + diff --git a/gst-libs/gst/pbutils/pbutils.c b/gst-libs/gst/pbutils/pbutils.c new file mode 100644 index 0000000..e3248af --- /dev/null +++ b/gst-libs/gst/pbutils/pbutils.c @@ -0,0 +1,51 @@ +/* GStreamer base utils library + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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; +} diff --git a/gst-libs/gst/pbutils/pbutils.h b/gst-libs/gst/pbutils/pbutils.h new file mode 100644 index 0000000..10c62d3 --- /dev/null +++ b/gst-libs/gst/pbutils/pbutils.h @@ -0,0 +1,35 @@ +/* GStreamer base utils library + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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 + +#include +#include + +G_BEGIN_DECLS + +void gst_base_utils_init (void); + +G_END_DECLS + +#endif /* __GST_BASE_UTILS_BASE_UTILS_H__ */ + diff --git a/gst-libs/gst/utils/Makefile.am b/gst-libs/gst/utils/Makefile.am new file mode 100644 index 0000000..2ba8f6b --- /dev/null +++ b/gst-libs/gst/utils/Makefile.am @@ -0,0 +1,19 @@ +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) diff --git a/gst-libs/gst/utils/base-utils.c b/gst-libs/gst/utils/base-utils.c new file mode 100644 index 0000000..e3248af --- /dev/null +++ b/gst-libs/gst/utils/base-utils.c @@ -0,0 +1,51 @@ +/* GStreamer base utils library + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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; +} diff --git a/gst-libs/gst/utils/base-utils.h b/gst-libs/gst/utils/base-utils.h new file mode 100644 index 0000000..10c62d3 --- /dev/null +++ b/gst-libs/gst/utils/base-utils.h @@ -0,0 +1,35 @@ +/* GStreamer base utils library + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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 + +#include +#include + +G_BEGIN_DECLS + +void gst_base_utils_init (void); + +G_END_DECLS + +#endif /* __GST_BASE_UTILS_BASE_UTILS_H__ */ + diff --git a/gst-libs/gst/utils/descriptions.c b/gst-libs/gst/utils/descriptions.c new file mode 100644 index 0000000..6bcb9a5 --- /dev/null +++ b/gst-libs/gst/utils/descriptions.c @@ -0,0 +1,898 @@ +/* GStreamer base utils library source/sink/codec description support + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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 + +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 diff --git a/gst-libs/gst/utils/descriptions.h b/gst-libs/gst/utils/descriptions.h new file mode 100644 index 0000000..9cba0b8 --- /dev/null +++ b/gst-libs/gst/utils/descriptions.h @@ -0,0 +1,58 @@ +/* GStreamer base utils library source/sink/codec description support + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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 +#include + +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__ */ + diff --git a/gst-libs/gst/utils/missing-plugins.c b/gst-libs/gst/utils/missing-plugins.c new file mode 100644 index 0000000..aa6581a --- /dev/null +++ b/gst-libs/gst/utils/missing-plugins.c @@ -0,0 +1,545 @@ +/* GStreamer base utils library missing plugins support + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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 +#endif +#ifdef HAVE_UNISTD_H +# include /* getpid on UNIX */ +#endif +#ifdef HAVE_PROCESS_H +# include /* getpid on win32 */ +#endif + +#include "gst/gst-i18n-plugin.h" + +#include "base-utils.h" + +#include + +#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"); +} diff --git a/gst-libs/gst/utils/missing-plugins.h b/gst-libs/gst/utils/missing-plugins.h new file mode 100644 index 0000000..25661f2 --- /dev/null +++ b/gst-libs/gst/utils/missing-plugins.h @@ -0,0 +1,60 @@ +/* GStreamer base utils library missing plugins support + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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 +#include + +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__ */ + diff --git a/pkgconfig/gstreamer-plugins-base-uninstalled.pc.in b/pkgconfig/gstreamer-plugins-base-uninstalled.pc.in index 9980db0..033fcba 100644 --- a/pkgconfig/gstreamer-plugins-base-uninstalled.pc.in +++ b/pkgconfig/gstreamer-plugins-base-uninstalled.pc.in @@ -9,7 +9,7 @@ Description: Streaming media framework, base plugins libraries, uninstalled 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 diff --git a/pkgconfig/gstreamer-plugins-base.pc.in b/pkgconfig/gstreamer-plugins-base.pc.in index 0a8bd2e..c6bdf33 100644 --- a/pkgconfig/gstreamer-plugins-base.pc.in +++ b/pkgconfig/gstreamer-plugins-base.pc.in @@ -11,4 +11,4 @@ Version: @VERSION@ 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 diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index c62552b..43144f3 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -78,6 +78,7 @@ check_PROGRAMS = \ libs/cddabasesrc \ libs/tag \ libs/video \ + libs/utils \ pipelines/simple-launch-lines # TORTURE_TO_FIX = \ @@ -137,10 +138,15 @@ libs_tag_CFLAGS = \ 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) diff --git a/tests/check/libs/.gitignore b/tests/check/libs/.gitignore index f63e043..f9a4a04 100644 --- a/tests/check/libs/.gitignore +++ b/tests/check/libs/.gitignore @@ -1,6 +1,7 @@ .dirstamp -cddabasesrc -video audio -tag +cddabasesrc netbuffer +tag +utils +video diff --git a/tests/check/libs/pbutils.c b/tests/check/libs/pbutils.c new file mode 100644 index 0000000..342691f --- /dev/null +++ b/tests/check/libs/pbutils.c @@ -0,0 +1,447 @@ +/* GStreamer unit tests for libgstbaseutils + * + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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 +#endif + +#include +#include +#include + +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); diff --git a/tests/check/libs/utils.c b/tests/check/libs/utils.c new file mode 100644 index 0000000..342691f --- /dev/null +++ b/tests/check/libs/utils.c @@ -0,0 +1,447 @@ +/* GStreamer unit tests for libgstbaseutils + * + * Copyright (C) 2006 Tim-Philipp Müller + * + * 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 +#endif + +#include +#include +#include + +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); -- 2.7.4