1 /* GStreamer Plugins Base utils library source/sink/codec description support
2 * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * SECTION:gstpbutilsdescriptions
22 * @short_description: Provides human-readable descriptions for caps/codecs
23 * and encoder, decoder, URI source and URI sink elements
27 * The above functions provide human-readable strings for media formats
28 * and decoder/demuxer/depayloader/encoder/muxer/payloader elements for use
29 * in error dialogs or other messages shown to users.
32 * gst_pb_utils_add_codec_description_to_tag_list() is a utility function
33 * for demuxer and decoder elements to add audio/video codec tags from a
34 * given (fixed) #GstCaps.
43 #include "gst/gst-i18n-plugin.h"
46 #include "pbutils-private.h"
52 FLAG_CONTAINER = (1 << 0), /* format is a container format (muxed) */
53 FLAG_SYSTEMSTREAM = (1 << 1) /* match record only if caps have systemstream=true */
63 static const FormatInfo formats[] = {
64 /* container/tag formats with static descriptions */
65 {"application/gxf", "General Exchange Format (GXF)", FLAG_CONTAINER},
66 {"application/ogg", "Ogg", FLAG_CONTAINER},
67 {"application/mxf", "Material eXchange Format (MXF)", FLAG_CONTAINER},
68 {"application/vnd.rn-realmedia", "Realmedia", FLAG_CONTAINER},
69 {"application/x-annodex", "Ogg", FLAG_CONTAINER},
70 {"application/x-id3", N_("ID3 tag"), FLAG_CONTAINER},
71 {"application/x-ape", N_("APE tag"), FLAG_CONTAINER},
72 {"application/x-apetag", N_("APE tag"), FLAG_CONTAINER},
73 {"application/x-icy", N_("ICY internet radio"), FLAG_CONTAINER},
74 {"application/x-3gp", "3GP", FLAG_CONTAINER},
75 {"application/x-pn-realaudio", "RealAudio", FLAG_CONTAINER},
76 {"application/x-yuv4mpeg", "Y4M", FLAG_CONTAINER},
77 {"multipart/x-mixed-replace", "Multipart", FLAG_CONTAINER},
78 {"video/x-fli", "FLI/FLC/FLX Animation", FLAG_CONTAINER},
79 {"video/x-flv", "Flash", FLAG_CONTAINER},
80 {"video/x-matroska", "Matroska", FLAG_CONTAINER},
81 {"video/webm", "WebM", FLAG_CONTAINER},
82 {"video/x-ms-asf", "Advanced Streaming Format (ASF)", FLAG_CONTAINER},
83 {"video/x-msvideo", "Audio Video Interleave (AVI)", FLAG_CONTAINER},
84 {"video/x-quicktime", "Quicktime", FLAG_CONTAINER},
85 {"video/quicktime", "Quicktime", FLAG_CONTAINER},
86 {"video/mj2", "Motion JPEG 2000", FLAG_CONTAINER},
88 /* audio formats with static descriptions */
89 {"audio/x-ac3", "AC-3 (ATSC A/52)", 0},
90 {"audio/ac3", "AC-3 (ATSC A/52)", 0},
91 {"audio/x-private-ac3", "DVD AC-3 (ATSC A/52)", 0},
92 {"audio/x-private1-ac3", "DVD AC-3 (ATSC A/52)", 0},
93 {"audio/x-alaw", "A-Law", 0},
94 {"audio/amr", "Adaptive Multi Rate (AMR)", 0},
95 {"audio/AMR", "Adaptive Multi Rate (AMR)", 0},
96 {"audio/AMR-WB", "Adaptive Multi Rate WideBand (AMR-WB)", 0},
97 {"audio/iLBC-sh", "Internet Low Bitrate Codec (iLBC)", 0},
98 {"audio/ms-gsm", "MS GSM", 0},
99 {"audio/qcelp", "QCELP", 0},
100 {"audio/aiff", "Audio Interchange File Format (AIFF)", 0},
101 {"audio/x-aiff", "Audio Interchange File Format (AIFF)", 0},
102 {"audio/x-alac", N_("Apple Lossless Audio (ALAC)"), 0},
103 {"audio/x-amr-nb-sh", "Adaptive Multi Rate NarrowBand (AMR-NB)", 0},
104 {"audio/x-amr-wb-sh", "Adaptive Multi Rate WideBand (AMR-WB)", 0},
105 {"audio/x-au", "Sun .au", 0},
106 {"audio/x-celt", "Constrained Energy Lapped Transform (CELT)", 0},
107 {"audio/x-cinepak", "Cinepak Audio", 0},
108 {"audio/x-dpcm", "DPCM", 0},
109 {"audio/x-dts", "DTS", 0},
110 {"audio/x-private1-dts", "DTS", 0},
111 {"audio/x-dv", "DV Audio", 0},
112 {"audio/x-flac", N_("Free Lossless Audio Codec (FLAC)"), 0},
113 {"audio/x-gsm", "GSM", 0},
114 {"audio/x-iec958", "S/PDIF IEC958", 0}, /* TODO: check description */
115 {"audio/x-iLBC", "Internet Low Bitrate Codec (iLBC)", 0},
116 {"audio/x-ircam", "Berkeley/IRCAM/CARL", 0},
117 {"audio/x-lpcm", "LPCM", 0},
118 {"audio/x-private1-lpcm", "DVD LPCM", 0},
119 {"audio/x-m4a", "MPEG-4 AAC", FLAG_CONTAINER},
120 {"audio/x-mod", "Module Music Format (MOD)", 0},
121 {"audio/x-mulaw", "Mu-Law", 0},
122 {"audio/x-musepack", "Musepack (MPC)", 0},
123 {"audio/x-nellymoser", "Nellymoser Asao", 0},
124 {"audio/x-nist", "Sphere NIST", 0},
125 {"audio/x-nsf", "Nintendo NSF", 0},
126 {"audio/x-paris", "Ensoniq PARIS", 0},
127 {"audio/x-qdm", "QDesign Music (QDM)", 0},
128 {"audio/x-qdm2", "QDesign Music (QDM) 2", 0},
129 {"audio/x-ralf-mpeg4-generic", "Real Audio Lossless (RALF)", 0},
130 {"audio/x-sds", "SDS", 0},
131 {"audio/x-shorten", "Shorten Lossless", 0},
132 {"audio/x-sid", "Sid", 0},
133 {"audio/x-sipro", "Sipro/ACELP.NET Voice", 0},
134 {"audio/x-siren", "Siren", 0},
135 {"audio/x-spc", "SNES-SPC700 Sound File Data", 0},
136 {"audio/x-speex", "Speex", 0},
137 {"audio/x-svx", "Amiga IFF / SVX8 / SV16", 0},
138 {"audio/x-tta", N_("Lossless True Audio (TTA)"), 0},
139 {"audio/x-ttafile", N_("Lossless True Audio (TTA)"), 0},
140 {"audio/x-vnd.sony.atrac3", "Sony ATRAC3", 0},
141 {"audio/x-vorbis", "Vorbis", 0},
142 {"audio/x-voc", "SoundBlaster VOC", 0},
143 {"audio/x-w64", "Sonic Foundry Wave64", 0},
144 {"audio/x-wav", "WAV", 0},
145 {"audio/x-wavpack", "Wavpack", 0},
146 {"audio/x-wavpack-correction", "Wavpack", 0},
147 {"audio/x-wms", N_("Windows Media Speech"), 0},
148 {"audio/x-voxware", "Voxware", 0},
151 /* video formats with static descriptions */
152 {"video/sp5x", "Sunplus JPEG 5.x", 0},
153 {"video/vivo", "Vivo", 0},
154 {"video/x-3ivx", "3ivx", 0},
155 {"video/x-4xm", "4X Technologies Video", 0},
156 {"video/x-apple-video", "Apple video", 0},
157 {"video/x-aasc", "Autodesk Animator", 0},
158 {"video/x-camtasia", "TechSmith Camtasia", 0},
159 {"video/x-cdxa", "RIFF/CDXA (VCD)", 0},
160 {"video/x-cinepak", "Cinepak Video", 0},
161 {"video/x-cirrus-logic-accupak", "Cirrus Logipak AccuPak", 0},
162 {"video/x-compressed-yuv", N_("CYUV Lossless"), 0},
163 {"video/x-dirac", "Dirac", 0},
164 {"video/x-dnxhd", "Digital Nonlinear Extensible High Definition (DNxHD)", 0},
165 /* FIXME 0.11: rename to subpicture/x-dvd or so */
166 {"video/x-dvd-subpicture", "DVD subpicture", 0},
167 {"video/x-ffv", N_("FFMpeg v1"), 0},
168 {"video/x-flash-screen", "Flash Screen Video", 0},
169 {"video/x-flash-video", "Sorenson Spark Video", 0},
170 {"video/x-h261", "H.261", 0},
171 {"video/x-huffyuv", "Huffyuv", 0},
172 {"video/x-intel-h263", "Intel H.263", 0},
173 {"video/x-jpeg", "Motion JPEG", 0},
174 /* { "video/x-jpeg-b", "", 0 }, does this actually exist? */
175 {"video/x-loco", "LOCO Lossless", 0},
176 {"video/x-mimic", "MIMIC", 0},
177 {"video/x-mjpeg", "Motion-JPEG", 0},
178 {"video/x-mjpeg-b", "Motion-JPEG format B", 0},
179 {"video/mpegts", "MPEG-2 Transport Stream", FLAG_CONTAINER},
180 {"video/x-mng", "Multiple Image Network Graphics (MNG)", 0},
181 {"video/x-mszh", N_("Lossless MSZH"), 0},
182 {"video/x-msvideocodec", "Microsoft Video 1", 0},
183 {"video/x-mve", "Interplay MVE", FLAG_CONTAINER},
184 {"video/x-nut", "NUT", FLAG_CONTAINER},
185 {"video/x-nuv", "MythTV NuppelVideo (NUV)", FLAG_CONTAINER},
186 {"video/x-qdrw", "Apple QuickDraw", 0},
187 {"video/x-raw-gray", N_("Uncompressed Gray Image"), 0},
188 {"video/x-smc", "Apple SMC", 0},
189 {"video/x-smoke", "Smoke", 0},
190 {"video/x-tarkin", "Tarkin", 0},
191 {"video/x-theora", "Theora", 0},
192 {"video/x-rle", N_("Run-length encoding"), 0},
193 {"video/x-ultimotion", "IBM UltiMotion", 0},
194 {"video/x-vcd", "VideoCD (VCD)", 0},
195 {"video/x-vmnc", "VMWare NC", 0},
196 {"video/x-vp3", "On2 VP3", 0},
197 {"video/x-vp5", "On2 VP5", 0},
198 {"video/x-vp6", "On2 VP6", 0},
199 {"video/x-vp6-flash", "On2 VP6/Flash", 0},
200 {"video/x-vp6-alpha", "On2 VP6 with alpha", 0},
201 {"video/x-vp7", "On2 VP7", 0},
202 {"video/x-vp8", "VP8", 0},
203 {"video/x-xvid", "XVID MPEG-4", 0},
204 {"video/x-zlib", "Lossless zlib video", 0},
205 {"video/x-zmbv", "Zip Motion Block video", 0},
207 /* image formats with static descriptions */
208 {"image/bmp", "BMP", 0},
209 {"image/x-bmp", "BMP", 0},
210 {"image/x-MS-bmp", "BMP", 0},
211 {"image/gif", "GIF", 0},
212 {"image/jpeg", "JPEG", 0},
213 {"image/jng", "JPEG Network Graphics (JNG)", 0},
214 {"image/png", "PNG", 0},
215 {"image/pbm", "Portable BitMap (PBM)", 0},
216 {"image/ppm", "Portable PixMap (PPM)", 0},
217 {"image/svg+xml", "Scalable Vector Graphics (SVG)", 0},
218 {"image/tiff", "TIFF", 0},
219 {"image/x-cmu-raster", "CMU Raster Format", 0},
220 {"image/x-degas", "DEGAS", 0},
221 {"image/x-icon", "ICO", 0},
222 {"image/x-j2c", "JPEG 2000", 0},
223 {"image/x-jpc", "JPEG 2000", 0},
224 {"image/jp2", "JPEG 2000", 0},
225 {"image/x-pcx", "PCX", 0},
226 {"image/x-xcf", "XFC", 0},
227 {"image/x-pixmap", "XPM", 0},
228 {"image/x-portable-anymap", "Portable AnyMap (PAM)", 0},
229 {"image/x-portable-graymap", "Portable GrayMap (PGM)", 0},
230 {"image/x-xpixmap", "XPM", 0},
231 {"image/x-quicktime", "QuickTime Image Format (QTIF)", 0},
232 {"image/x-sun-raster", "Sun Raster Format (RAS)", 0},
233 {"image/x-tga", "TGA", 0},
234 {"image/vnd.wap.wbmp", "Wireless Bitmap", 0},
236 /* subtitle formats with static descriptions */
237 {"application/x-ass", "ASS", 0},
238 {"application/x-subtitle-sami", N_("Sami subtitle format"), 0},
239 {"application/x-subtitle-tmplayer", N_("TMPlayer subtitle format"), 0},
240 {"application/x-kate", "Kate", 0},
241 {"subtitle/x-kate", N_("Kate subtitle format"), 0},
242 {"subpicture/x-dvb", "DVB subtitles", 0},
243 /* add variant field to typefinder? { "application/x-subtitle", N_("subtitle"), 0}, */
245 /* non-audio/video/container formats */
246 {"hdv/aux-v", "HDV AUX-V", 0},
247 {"hdv/aux-a", "HDV AUX-A", 0},
249 /* formats with dynamic descriptions */
250 {"audio/mpeg", NULL, 0},
251 {"audio/x-adpcm", NULL, 0},
252 {"audio/x-mace", NULL, 0},
253 {"audio/x-pn-realaudio", NULL, 0},
254 {"audio/x-raw-int", NULL, 0},
255 {"audio/x-raw-float", NULL, 0},
256 {"audio/x-wma", NULL, 0},
257 {"video/mpeg", NULL, FLAG_CONTAINER | FLAG_SYSTEMSTREAM},
258 {"video/mpeg", NULL, 0},
259 {"video/x-asus", NULL, 0},
260 {"video/x-ati-vcr", NULL, 0},
261 {"video/x-divx", NULL, 0},
262 {"video/x-dv", "Digital Video (DV) System Stream",
263 FLAG_CONTAINER | FLAG_SYSTEMSTREAM},
264 {"video/x-dv", "Digital Video (DV)", 0},
265 {"video/x-h263", NULL, 0},
266 {"video/x-h264", NULL, 0},
267 {"video/x-indeo", NULL, 0},
268 {"video/x-msmpeg", NULL, 0},
269 {"video/x-pn-realvideo", NULL, 0},
271 /* do these exist? are they used anywhere? */
272 {"video/x-pn-multirate-realvideo", NULL, 0},
273 {"audio/x-pn-multirate-realaudio", NULL, 0},
274 {"audio/x-pn-multirate-realaudio-live", NULL, 0},
276 {"video/x-truemotion", NULL, 0},
277 {"video/x-raw-rgb", NULL, 0},
278 {"video/x-raw-yuv", NULL, 0},
279 {"video/x-svq", NULL, 0},
280 {"video/x-wmv", NULL, 0},
281 {"video/x-xan", NULL, 0}
284 /* returns static descriptions and dynamic ones (such as video/x-raw-yuv),
285 * or NULL if caps aren't known at all */
287 format_info_get_desc (const FormatInfo * info, const GstCaps * caps)
289 const GstStructure *s;
291 g_assert (info != NULL);
293 if (info->desc != NULL)
294 return g_strdup (_(info->desc));
296 s = gst_caps_get_structure (caps, 0);
298 if (strcmp (info->type, "video/x-raw-yuv") == 0) {
299 const gchar *ret = NULL;
302 gst_structure_get_fourcc (s, "format", &fourcc);
304 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
305 ret = _("Uncompressed planar YUV 4:2:0");
307 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
308 ret = _("Uncompressed planar YVU 4:2:0");
310 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
311 ret = _("Uncompressed packed YUV 4:2:2");
313 case GST_MAKE_FOURCC ('Y', 'U', 'V', '9'):
314 ret = _("Uncompressed packed YUV 4:1:0");
316 case GST_MAKE_FOURCC ('Y', 'V', 'U', '9'):
317 ret = _("Uncompressed packed YVU 4:1:0");
319 case GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U'):
320 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
321 ret = _("Uncompressed packed YUV 4:2:2");
323 case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
324 ret = _("Uncompressed packed YUV 4:1:1");
326 case GST_MAKE_FOURCC ('I', 'Y', 'U', '2'):
327 ret = _("Uncompressed packed YUV 4:4:4");
329 case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
330 ret = _("Uncompressed planar YUV 4:2:2");
332 case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
333 ret = _("Uncompressed planar YUV 4:1:1");
335 case GST_MAKE_FOURCC ('Y', '8', '0', '0'):
336 ret = _("Uncompressed black and white Y-plane");
339 ret = _("Uncompressed YUV");
342 return g_strdup (ret);
343 } else if (strcmp (info->type, "video/x-raw-rgb") == 0) {
344 const gchar *rgb_str;
347 gst_structure_get_int (s, "depth", &depth);
348 rgb_str = gst_structure_has_field (s, "alpha_mask") ? "RGBA" : "RGB";
349 if (gst_structure_has_field (s, "paletted_data")) {
350 return g_strdup_printf (_("Uncompressed palettized %d-bit %s"), depth,
353 return g_strdup_printf ("Uncompressed %d-bit %s", depth, rgb_str);
355 } else if (strcmp (info->type, "video/x-h263") == 0) {
356 const gchar *variant, *ret;
358 variant = gst_structure_get_string (s, "variant");
361 else if (strcmp (variant, "itu") == 0)
362 ret = "ITU H.26n"; /* why not ITU H.263? (tpm) */
363 else if (strcmp (variant, "lead") == 0)
365 else if (strcmp (variant, "microsoft") == 0)
366 ret = "Microsoft H.263";
367 else if (strcmp (variant, "vdolive") == 0)
369 else if (strcmp (variant, "vivo") == 0)
371 else if (strcmp (variant, "xirlink") == 0)
372 ret = "Xirlink H.263";
374 GST_WARNING ("Unknown H263 variant '%s'", variant);
377 return g_strdup (ret);
378 } else if (strcmp (info->type, "video/x-h264") == 0) {
379 const gchar *variant, *ret;
381 variant = gst_structure_get_string (s, "variant");
384 else if (strcmp (variant, "itu") == 0)
386 else if (strcmp (variant, "videosoft") == 0)
387 ret = "Videosoft H.264";
388 else if (strcmp (variant, "lead") == 0)
391 GST_WARNING ("Unknown H264 variant '%s'", variant);
394 return g_strdup (ret);
395 } else if (strcmp (info->type, "video/x-divx") == 0) {
398 if (!gst_structure_get_int (s, "divxversion", &ver) || ver <= 2) {
399 GST_WARNING ("Unexpected DivX version in %" GST_PTR_FORMAT, caps);
400 return g_strdup ("DivX MPEG-4");
402 return g_strdup_printf (_("DivX MPEG-4 Version %d"), ver);
403 } else if (strcmp (info->type, "video/x-msmpeg") == 0) {
406 if (!gst_structure_get_int (s, "msmpegversion", &ver) ||
407 ver < 40 || ver > 49) {
408 GST_WARNING ("Unexpected msmpegversion in %" GST_PTR_FORMAT, caps);
409 return g_strdup ("Microsoft MPEG-4 4.x");
411 return g_strdup_printf ("Microsoft MPEG-4 4.%d", ver % 10);
412 } else if (strcmp (info->type, "video/x-truemotion") == 0) {
415 gst_structure_get_int (s, "trueversion", &ver);
418 return g_strdup_printf ("Duck TrueMotion 1");
420 return g_strdup_printf ("TrueMotion 2.0");
422 GST_WARNING ("Unexpected trueversion in %" GST_PTR_FORMAT, caps);
425 return g_strdup_printf ("TrueMotion");
426 } else if (strcmp (info->type, "video/x-xan") == 0) {
429 if (!gst_structure_get_int (s, "wcversion", &ver) || ver < 1) {
430 GST_WARNING ("Unexpected wcversion in %" GST_PTR_FORMAT, caps);
431 return g_strdup ("Xan Wing Commander");
433 return g_strdup_printf ("Xan Wing Commander %u", ver);
434 } else if (strcmp (info->type, "video/x-indeo") == 0) {
437 if (!gst_structure_get_int (s, "indeoversion", &ver) || ver < 2) {
438 GST_WARNING ("Unexpected indeoversion in %" GST_PTR_FORMAT, caps);
439 return g_strdup ("Intel Indeo");
441 return g_strdup_printf ("Intel Indeo %u", ver);
442 } else if (strcmp (info->type, "audio/x-wma") == 0) {
445 gst_structure_get_int (s, "wmaversion", &ver);
450 return g_strdup_printf ("Windows Media Audio %d", ver + 6);
454 GST_WARNING ("Unexpected wmaversion in %" GST_PTR_FORMAT, caps);
455 return g_strdup ("Windows Media Audio");
456 } else if (strcmp (info->type, "video/x-wmv") == 0) {
459 gst_structure_get_int (s, "wmvversion", &ver);
464 return g_strdup_printf ("Windows Media Video %d", ver + 6);
468 GST_WARNING ("Unexpected wmvversion in %" GST_PTR_FORMAT, caps);
469 return g_strdup ("Windows Media Video");
470 } else if (strcmp (info->type, "audio/x-mace") == 0) {
473 gst_structure_get_int (s, "maceversion", &ver);
474 if (ver == 3 || ver == 6) {
475 return g_strdup_printf ("MACE-%d", ver);
477 GST_WARNING ("Unexpected maceversion in %" GST_PTR_FORMAT, caps);
478 return g_strdup ("MACE");
480 } else if (strcmp (info->type, "video/x-svq") == 0) {
483 gst_structure_get_int (s, "svqversion", &ver);
484 if (ver == 1 || ver == 3) {
485 return g_strdup_printf ("Sorensen Video %d", ver);
487 GST_WARNING ("Unexpected svqversion in %" GST_PTR_FORMAT, caps);
488 return g_strdup ("Sorensen Video");
490 } else if (strcmp (info->type, "video/x-asus") == 0) {
493 gst_structure_get_int (s, "asusversion", &ver);
494 if (ver == 1 || ver == 2) {
495 return g_strdup_printf ("Asus Video %d", ver);
497 GST_WARNING ("Unexpected asusversion in %" GST_PTR_FORMAT, caps);
498 return g_strdup ("Asus Video");
500 } else if (strcmp (info->type, "video/x-ati-vcr") == 0) {
503 gst_structure_get_int (s, "vcrversion", &ver);
504 if (ver == 1 || ver == 2) {
505 return g_strdup_printf ("ATI VCR %d", ver);
507 GST_WARNING ("Unexpected acrversion in %" GST_PTR_FORMAT, caps);
508 return g_strdup ("ATI VCR");
510 } else if (strcmp (info->type, "audio/x-adpcm") == 0) {
511 const GValue *layout_val;
513 layout_val = gst_structure_get_value (s, "layout");
514 if (layout_val != NULL && G_VALUE_HOLDS_STRING (layout_val)) {
517 if ((layout = g_value_get_string (layout_val))) {
518 gchar *layout_upper, *ret;
520 if (strcmp (layout, "swf") == 0)
521 return g_strdup ("Shockwave ADPCM");
522 if (strcmp (layout, "microsoft") == 0)
523 return g_strdup ("Microsoft ADPCM");
524 if (strcmp (layout, "quicktime") == 0)
525 return g_strdup ("Quicktime ADPCM");
526 if (strcmp (layout, "westwood") == 0)
527 return g_strdup ("Westwood ADPCM");
528 if (strcmp (layout, "yamaha") == 0)
529 return g_strdup ("Yamaha ADPCM");
530 /* FIXME: other layouts: sbpro2, sbpro3, sbpro4, ct, g726, ea,
531 * adx, xa, 4xm, smjpeg, dk4, dk3, dvi */
532 layout_upper = g_ascii_strup (layout, -1);
533 ret = g_strdup_printf ("%s ADPCM", layout_upper);
534 g_free (layout_upper);
538 return g_strdup ("ADPCM");
539 } else if (strcmp (info->type, "audio/mpeg") == 0) {
540 gint ver = 0, layer = 0;
542 gst_structure_get_int (s, "mpegversion", &ver);
546 gst_structure_get_int (s, "layer", &layer);
551 return g_strdup_printf ("MPEG-1 Layer %d (MP%d)", layer, layer);
555 GST_WARNING ("Unexpected MPEG-1 layer in %" GST_PTR_FORMAT, caps);
556 return g_strdup ("MPEG-1 Audio");
558 return g_strdup ("MPEG-4 AAC");
562 GST_WARNING ("Unexpected audio mpegversion in %" GST_PTR_FORMAT, caps);
563 return g_strdup ("MPEG Audio");
564 } else if (strcmp (info->type, "audio/x-pn-realaudio") == 0) {
567 gst_structure_get_int (s, "raversion", &ver);
570 return g_strdup ("RealAudio 14k4bps");
572 return g_strdup ("RealAudio 28k8bps");
574 return g_strdup ("RealAudio G2 (Cook)");
578 GST_WARNING ("Unexpected raversion in %" GST_PTR_FORMAT, caps);
579 return g_strdup ("RealAudio");
580 } else if (strcmp (info->type, "video/x-pn-realvideo") == 0) {
583 gst_structure_get_int (s, "rmversion", &ver);
586 return g_strdup ("RealVideo 1.0");
588 return g_strdup ("RealVideo 2.0");
590 return g_strdup ("RealVideo 3.0");
592 return g_strdup ("RealVideo 4.0");
596 GST_WARNING ("Unexpected rmversion in %" GST_PTR_FORMAT, caps);
597 return g_strdup ("RealVideo");
598 } else if (strcmp (info->type, "video/mpeg") == 0) {
602 if (!gst_structure_get_boolean (s, "systemstream", &sysstream) ||
603 !gst_structure_get_int (s, "mpegversion", &ver) || ver < 1 || ver > 4) {
604 GST_WARNING ("Missing fields in mpeg video caps %" GST_PTR_FORMAT, caps);
607 return g_strdup_printf ("MPEG-%d System Stream", ver);
609 return g_strdup_printf ("MPEG-%d Video", ver);
612 return g_strdup ("MPEG Video");
613 } else if (strcmp (info->type, "audio/x-raw-int") == 0) {
616 /* 8-bit pcm might not have depth field (?) */
617 if (!gst_structure_get_int (s, "depth", &bitdepth))
618 gst_structure_get_int (s, "width", &bitdepth);
620 return g_strdup_printf (_("Raw %d-bit PCM audio"), bitdepth);
622 return g_strdup (_("Raw PCM audio"));
623 } else if (strcmp (info->type, "audio/x-raw-float") == 0) {
626 gst_structure_get_int (s, "width", &bitdepth);
628 return g_strdup_printf (_("Raw %d-bit floating-point audio"), bitdepth);
630 return g_strdup (_("Raw floating-point audio"));
636 /* returns format info structure, will return NULL for dynamic media types! */
637 static const FormatInfo *
638 find_format_info (const GstCaps * caps)
640 const GstStructure *s;
641 const gchar *media_type;
644 s = gst_caps_get_structure (caps, 0);
645 media_type = gst_structure_get_name (s);
647 for (i = 0; i < G_N_ELEMENTS (formats); ++i) {
648 if (strcmp (media_type, formats[i].type) == 0) {
649 gboolean is_sys = FALSE;
651 if ((formats[i].flags & FLAG_SYSTEMSTREAM) == 0)
654 /* this record should only be matched if the systemstream field is set */
655 if (gst_structure_get_boolean (s, "systemstream", &is_sys) && is_sys)
664 caps_are_rtp_caps (const GstCaps * caps, const gchar * media, gchar ** format)
666 const GstStructure *s;
669 g_assert (media != NULL && format != NULL);
671 s = gst_caps_get_structure (caps, 0);
672 if (!gst_structure_has_name (s, "application/x-rtp"))
674 if (!gst_structure_has_field_typed (s, "media", G_TYPE_STRING))
676 str = gst_structure_get_string (s, "media");
677 if (str == NULL || !g_str_equal (str, media))
679 str = gst_structure_get_string (s, "encoding-name");
680 if (str == NULL || *str == '\0')
683 if (strcmp (str, "X-ASF-PF") == 0) {
684 *format = g_strdup ("Windows Media");
685 } else if (g_str_has_prefix (str, "X-")) {
686 *format = g_strdup (str + 2);
688 *format = g_strdup (str);
695 * gst_pb_utils_get_source_description:
696 * @protocol: the protocol the source element needs to handle, e.g. "http"
698 * Returns a localised string describing a source element handling the protocol
699 * specified in @protocol, for use in error dialogs or other messages to be
700 * seen by the user. Should never return NULL unless @protocol is invalid.
702 * This function is mainly for internal use, applications would typically
703 * use gst_missing_plugin_message_get_description() to get a description of
704 * a missing feature from a missing-plugin message.
706 * Returns: a newly-allocated description string, or NULL on error. Free
707 * string with g_free() when not needed any longer.
710 gst_pb_utils_get_source_description (const gchar * protocol)
712 gchar *proto_uc, *ret;
714 g_return_val_if_fail (protocol != NULL, NULL);
716 if (strcmp (protocol, "cdda") == 0)
717 return g_strdup (_("Audio CD source"));
719 if (strcmp (protocol, "dvd") == 0)
720 return g_strdup (_("DVD source"));
722 if (strcmp (protocol, "rtsp") == 0)
723 return g_strdup (_("Real Time Streaming Protocol (RTSP) source"));
725 /* TODO: what about mmst, mmsu, mmsh? */
726 if (strcmp (protocol, "mms") == 0)
727 return g_strdup (_("Microsoft Media Server (MMS) protocol source"));
729 /* make protocol uppercase */
730 proto_uc = g_ascii_strup (protocol, -1);
732 /* TODO: find out how to add a comment for translators to the source code
733 * (and tell them to make the first letter uppercase below if they move
734 * the protocol to the middle or end of the string) */
735 ret = g_strdup_printf (_("%s protocol source"), proto_uc);
743 * gst_pb_utils_get_sink_description:
744 * @protocol: the protocol the sink element needs to handle, e.g. "http"
746 * Returns a localised string describing a sink element handling the protocol
747 * specified in @protocol, for use in error dialogs or other messages to be
748 * seen by the user. Should never return NULL unless @protocol is invalid.
750 * This function is mainly for internal use, applications would typically
751 * use gst_missing_plugin_message_get_description() to get a description of
752 * a missing feature from a missing-plugin message.
754 * Returns: a newly-allocated description string, or NULL on error. Free
755 * string with g_free() when not needed any longer.
758 gst_pb_utils_get_sink_description (const gchar * protocol)
760 gchar *proto_uc, *ret;
762 g_return_val_if_fail (protocol != NULL, NULL);
764 /* make protocol uppercase */
765 proto_uc = g_ascii_strup (protocol, -1);
767 /* TODO: find out how to add a comment for translators to the source code
768 * (and tell them to make the first letter uppercase below if they move
769 * the protocol to the middle or end of the string) */
770 ret = g_strdup_printf ("%s protocol sink", proto_uc);
778 * gst_pb_utils_get_decoder_description:
779 * @caps: the (fixed) #GstCaps for which an decoder description is needed
781 * Returns a localised string describing an decoder for the format specified
782 * in @caps, for use in error dialogs or other messages to be seen by the user.
783 * Should never return NULL unless @factory_name or @caps are invalid.
785 * This function is mainly for internal use, applications would typically
786 * use gst_missing_plugin_message_get_description() to get a description of
787 * a missing feature from a missing-plugin message.
789 * Returns: a newly-allocated description string, or NULL on error. Free
790 * string with g_free() when not needed any longer.
793 gst_pb_utils_get_decoder_description (const GstCaps * caps)
798 g_return_val_if_fail (caps != NULL, NULL);
799 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
801 tmp = copy_and_clean_caps (caps);
803 g_return_val_if_fail (gst_caps_is_fixed (tmp), NULL);
805 /* special-case RTP caps */
806 if (caps_are_rtp_caps (tmp, "video", &str)) {
807 ret = g_strdup_printf (_("%s video RTP depayloader"), str);
808 } else if (caps_are_rtp_caps (tmp, "audio", &str)) {
809 ret = g_strdup_printf (_("%s audio RTP depayloader"), str);
810 } else if (caps_are_rtp_caps (tmp, "application", &str)) {
811 ret = g_strdup_printf (_("%s RTP depayloader"), str);
813 const FormatInfo *info;
815 str = gst_pb_utils_get_codec_description (tmp);
816 info = find_format_info (tmp);
817 if (info != NULL && (info->flags & FLAG_CONTAINER) != 0) {
818 ret = g_strdup_printf (_("%s demuxer"), str);
820 ret = g_strdup_printf (_("%s decoder"), str);
825 gst_caps_unref (tmp);
831 * gst_pb_utils_get_encoder_description:
832 * @caps: the (fixed) #GstCaps for which an encoder description is needed
834 * Returns a localised string describing an encoder for the format specified
835 * in @caps, for use in error dialogs or other messages to be seen by the user.
836 * Should never return NULL unless @factory_name or @caps are invalid.
838 * This function is mainly for internal use, applications would typically
839 * use gst_missing_plugin_message_get_description() to get a description of
840 * a missing feature from a missing-plugin message.
842 * Returns: a newly-allocated description string, or NULL on error. Free
843 * string with g_free() when not needed any longer.
846 gst_pb_utils_get_encoder_description (const GstCaps * caps)
851 g_return_val_if_fail (caps != NULL, NULL);
852 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
853 tmp = copy_and_clean_caps (caps);
854 g_return_val_if_fail (gst_caps_is_fixed (tmp), NULL);
856 /* special-case RTP caps */
857 if (caps_are_rtp_caps (tmp, "video", &str)) {
858 ret = g_strdup_printf (_("%s video RTP payloader"), str);
859 } else if (caps_are_rtp_caps (tmp, "audio", &str)) {
860 ret = g_strdup_printf (_("%s audio RTP payloader"), str);
861 } else if (caps_are_rtp_caps (tmp, "application", &str)) {
862 ret = g_strdup_printf (_("%s RTP payloader"), str);
864 const FormatInfo *info;
866 str = gst_pb_utils_get_codec_description (tmp);
867 info = find_format_info (tmp);
868 if (info != NULL && (info->flags & FLAG_CONTAINER) != 0) {
869 ret = g_strdup_printf (_("%s muxer"), str);
871 ret = g_strdup_printf (_("%s encoder"), str);
876 gst_caps_unref (tmp);
882 * gst_pb_utils_get_element_description:
883 * @factory_name: the name of the element, e.g. "gnomevfssrc"
885 * Returns a localised string describing the given element, for use in
886 * error dialogs or other messages to be seen by the user. Should never
887 * return NULL unless @factory_name is invalid.
889 * This function is mainly for internal use, applications would typically
890 * use gst_missing_plugin_message_get_description() to get a description of
891 * a missing feature from a missing-plugin message.
893 * Returns: a newly-allocated description string, or NULL on error. Free
894 * string with g_free() when not needed any longer.
897 gst_pb_utils_get_element_description (const gchar * factory_name)
901 g_return_val_if_fail (factory_name != NULL, NULL);
903 ret = g_strdup_printf (_("GStreamer element %s"), factory_name);
904 if (ret && g_str_has_prefix (ret, factory_name))
905 *ret = g_ascii_toupper (*ret);
911 * gst_pb_utils_add_codec_description_to_tag_list:
912 * @taglist: a #GstTagList
913 * @codec_tag: a GStreamer codec tag such as #GST_TAG_AUDIO_CODEC,
914 * #GST_TAG_VIDEO_CODEC or #GST_TAG_CODEC
915 * @caps: the (fixed) #GstCaps for which a codec tag should be added.
917 * Adds a codec tag describing the format specified by @caps to @taglist.
919 * Returns: TRUE if a codec tag was added, FALSE otherwise.
922 gst_pb_utils_add_codec_description_to_tag_list (GstTagList * taglist,
923 const gchar * codec_tag, const GstCaps * caps)
925 const FormatInfo *info;
928 g_return_val_if_fail (taglist != NULL, FALSE);
929 g_return_val_if_fail (GST_IS_TAG_LIST (taglist), FALSE);
930 g_return_val_if_fail (codec_tag != NULL, FALSE);
931 g_return_val_if_fail (gst_tag_exists (codec_tag), FALSE);
932 g_return_val_if_fail (gst_tag_get_type (codec_tag) == G_TYPE_STRING, FALSE);
933 g_return_val_if_fail (caps != NULL, FALSE);
934 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
936 info = find_format_info (caps);
940 desc = format_info_get_desc (info, caps);
941 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, codec_tag, desc, NULL);
948 * gst_pb_utils_get_codec_description:
949 * @caps: the (fixed) #GstCaps for which an format description is needed
951 * Returns a localised (as far as this is possible) string describing the
952 * media format specified in @caps, for use in error dialogs or other messages
953 * to be seen by the user. Should never return NULL unless @caps is invalid.
955 * Also see the convenience function
956 * gst_pb_utils_add_codec_description_to_tag_list().
958 * Returns: a newly-allocated description string, or NULL on error. Free
959 * string with g_free() when not needed any longer.
962 gst_pb_utils_get_codec_description (const GstCaps * caps)
964 const FormatInfo *info;
968 g_return_val_if_fail (caps != NULL, NULL);
969 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
970 tmp = copy_and_clean_caps (caps);
971 g_return_val_if_fail (gst_caps_is_fixed (tmp), NULL);
973 info = find_format_info (tmp);
976 str = format_info_get_desc (info, tmp);
978 str = gst_caps_to_string (tmp);
980 /* cut off everything after the media type, if there is anything */
981 if ((comma = strchr (str, ','))) {
984 /* we could do something more elaborate here, like taking into account
985 * audio/, video/, image/ and application/ prefixes etc. */
988 GST_WARNING ("No description available for media type: %s", str);
990 gst_caps_unref (tmp);
997 gst_pb_utils_list_all (void)
1001 g_print ("static const gchar *caps_strings[] = { ");
1003 for (i = 0; i < G_N_ELEMENTS (formats); ++i) {
1004 if (formats[i].desc != NULL)
1005 g_print (" \"%s\", ", formats[i].type);
1007 g_print ("\n#if 0\n");
1008 for (i = 0; i < G_N_ELEMENTS (formats); ++i) {
1009 if (formats[i].desc == NULL)
1010 g_print (" \"%s\", \n", formats[i].type);
1012 g_print ("\n#endif\n");