hythmbox-2.98/lib/rb-gst-media-types.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found rb-gst-media-types.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found rb-gst-media-types.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  1 /*
  2  *  Copyright (C) 2010  Jonathan Matthew  <jonathan@d14n.org>
  3  *
  4  *  This program is free software; you can redistribute it and/or modify
  5  *  it under the terms of the GNU General Public License as published by
  6  *  the Free Software Foundation; either version 2, or (at your option)
  7  *  any later version.
  8  *
  9  *  The Rhythmbox authors hereby grant permission for non-GPL compatible
 10  *  GStreamer plugins to be used and distributed together with GStreamer
 11  *  and Rhythmbox. This permission is above and beyond the permissions granted
 12  *  by the GPL license by which Rhythmbox is covered. If you modify this code
 13  *  you may extend this exception to your version of the code, but you are not
 14  *  obligated to do so. If you do not wish to do so, delete this exception
 15  *  statement from your version.
 16  *
 17  *  This program is distributed in the hope that it will be useful,
 18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 20  *  GNU General Public License for more details.
 21  *
 22  *  You should have received a copy of the GNU General Public License
 23  *  along with this program; if not, write to the Free Software
 24  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 25  *
 26  */
 27 
 28 #include "config.h"
 29 
 30 #include <memory.h>
 31 
 32 #include <gst/pbutils/encoding-target.h>
 33 
 34 #include <lib/rb-gst-media-types.h>
 35 #include <lib/rb-debug.h>
 36 #include <lib/rb-file-helpers.h>
 37 
 38 /* don't like this much, but it's all we can do for now.
 39  * these media types are copied from gst-plugins-base/gst-libs/gst/pbutils/descriptions.c.
 40  * these are only the media types that don't start with 'audio/' or 'video/', which are
 41  * identified fairly accurately by the filters for those prefixes.
 42  */
 43 static const char *container_formats[] = {
 44 	"application/ogg",
 45 	"application/vnd.rn-realmedia",
 46 	"application/x-id3",
 47 	"application/x-ape",
 48 	"application/x-icy"
 49 };
 50 
 51 #define ENCODING_TARGET_FILE "rhythmbox.gep"
 52 static GstEncodingTarget *default_target = NULL;
 53 static GKeyFile *target_keyfile = NULL;
 54 
 55 RBGstMediaType
 56 rb_gst_get_missing_plugin_type (const GstStructure *structure)
 57 {
 58 	const char *media_type;
 59 	const char *missing_type;
 60 	const GstCaps *caps;
 61 	const GValue *val;
 62 	int i;
 63 
 64 	if (structure == NULL) {
 65 		rb_debug ("no missing plugin details");
 66 		return MEDIA_TYPE_NONE;
 67 	}
 68 
 69 	missing_type = gst_structure_get_string (structure, "type");
 70 	if (missing_type == NULL || strcmp (missing_type, "decoder") != 0) {
 71 		rb_debug ("missing plugin is not a decoder");
 72 		return MEDIA_TYPE_NONE;
 73 	}
 74 
 75 	val = gst_structure_get_value (structure, "detail");
 76 	caps = gst_value_get_caps (val);
 77 
 78 	media_type = gst_structure_get_name (gst_caps_get_structure (caps, 0));
 79 	for (i = 0; i < G_N_ELEMENTS (container_formats); i++) {
 80 		if (strcmp (media_type, container_formats[i]) == 0) {
 81 			rb_debug ("missing plugin is a container demuxer");
 82 			return MEDIA_TYPE_CONTAINER;
 83 		}
 84 	}
 85 
 86 	if (g_str_has_prefix (media_type, "audio/")) {
 87 		rb_debug ("missing plugin is an audio decoder");
 88 		return MEDIA_TYPE_AUDIO;
 89 	} else if (g_str_has_prefix (media_type, "video/")) {
 90 		rb_debug ("missing plugin is (probably) a video decoder");
 91 		return MEDIA_TYPE_VIDEO;
 92 	} else {
 93 		rb_debug ("missing plugin is neither a video nor audio decoder");
 94 		return MEDIA_TYPE_OTHER;
 95 	}
 96 }
 97 
 98 char *
 99 rb_gst_caps_to_media_type (const GstCaps *caps)
100 {
101 	GstStructure *s;
102 	const char *media_type;
103 
104 	/* the aim here is to reduce the caps to a single mimetype-like
105 	 * string, describing the audio encoding (for audio files) or the
106 	 * file type (for everything else).  raw media types are ignored.
107 	 *
108 	 * there are only a couple of special cases.
109 	 */
110 
111 	if (gst_caps_get_size (caps) == 0)
112 		return NULL;
113 
114 	s = gst_caps_get_structure (caps, 0);
115 	media_type = gst_structure_get_name (s);
116 	if (media_type == NULL) {
117 		return NULL;
118 	} else if (g_str_has_prefix (media_type, "audio/x-raw-") ||
119 	    g_str_has_prefix (media_type, "video/x-raw-")) {
120 		/* ignore raw types */
121 		return NULL;
122 	} else if (g_str_equal (media_type, "audio/mpeg")) {
123 		/* need to distinguish between mpeg 1 layer 3 and
124 		 * mpeg 2 or 4 here.
125 		 */
126 		int mpegversion = 0;
127 		gst_structure_get_int (s, "mpegversion", &mpegversion);
128 		switch (mpegversion) {
129 		case 2:
130 		case 4:
131 			return g_strdup ("audio/x-aac");		/* hmm. */
132 
133 		case 1:
134 		default:
135 			return g_strdup ("audio/mpeg");
136 		}
137 	} else {
138 		/* everything else is fine as-is */
139 		return g_strdup (media_type);
140 	}
141 }
142 
143 GstCaps *
144 rb_gst_media_type_to_caps (const char *media_type)
145 {
146 	/* special cases: */
147 	if (strcmp (media_type, "audio/mpeg") == 0) {
148 		return gst_caps_from_string ("audio/mpeg, mpegversion=(int)1");
149 	} else if (strcmp (media_type, "audio/x-aac") == 0) {
150 		return gst_caps_from_string ("audio/mpeg, mpegversion=(int){ 2, 4 }");
151 	} else {
152 		/* otherwise, the media type is enough */
153 		return gst_caps_from_string (media_type);
154 	}
155 }
156 
157 const char *
158 rb_gst_media_type_to_extension (const char *media_type)
159 {
160 	if (media_type == NULL) {
161 		return NULL;
162 	} else if (!strcmp (media_type, "audio/mpeg")) {
163 		return "mp3";
164 	} else if (!strcmp (media_type, "audio/x-vorbis") || !strcmp (media_type, "application/ogg") || !strcmp (media_type, "audio/ogg")) {
165 		return "ogg";
166 	} else if (!strcmp (media_type, "audio/x-flac") || !strcmp (media_type, "audio/flac")) {
167 		return "flac";
168 	} else if (!strcmp (media_type, "audio/x-aac") || !strcmp (media_type, "audio/aac") || !strcmp (media_type, "audio/x-alac")) {
169 		return "m4a";
170 	} else if (!strcmp (media_type, "audio/x-wavpack")) {
171 		return "wv";
172 	} else {
173 		return NULL;
174 	}
175 }
176 
177 const char *
178 rb_gst_mime_type_to_media_type (const char *mime_type)
179 {
180 	if (!strcmp (mime_type, "application/x-id3") || !strcmp (mime_type, "audio/mpeg")) {
181 		return "audio/mpeg";
182 	} else if (!strcmp (mime_type, "application/ogg") || !strcmp (mime_type, "audio/x-vorbis") || !strcmp (mime_type, "audio/ogg")) {
183 		return "audio/x-vorbis";
184 	} else if (!strcmp (mime_type, "audio/flac")) {
185 		return "audio/x-flac";
186 	} else if (!strcmp (mime_type, "audio/aac") || !strcmp (mime_type, "audio/mp4") || !strcmp (mime_type, "audio/m4a")) {
187 		return "audio/x-aac";
188 	}
189 	return mime_type;
190 }
191 
192 const char *
193 rb_gst_media_type_to_mime_type (const char *media_type)
194 {
195 	if (!strcmp (media_type, "audio/x-vorbis")) {
196 		return "application/ogg";
197 	} else if (!strcmp (media_type, "audio/x-flac")) {
198 		return "audio/flac";
199 	} else if (!strcmp (media_type, "audio/x-aac")) {
200 		return "audio/mp4";	/* probably */
201 	} else {
202 		return media_type;
203 	}
204 }
205 
206 gboolean
207 rb_gst_media_type_matches_profile (GstEncodingProfile *profile, const char *media_type)
208 {
209 	const GstCaps *pcaps;
210 	const GList *cl;
211 	GstCaps *caps;
212 	gboolean matches = FALSE;
213 
214 	caps = rb_gst_media_type_to_caps (media_type);
215 	if (caps == NULL) {
216 		return FALSE;
217 	}
218 
219 	pcaps = gst_encoding_profile_get_format (profile);
220 	if (gst_caps_can_intersect (caps, pcaps)) {
221 		matches = TRUE;
222 	}
223 
224 	if (matches == FALSE && GST_IS_ENCODING_CONTAINER_PROFILE (profile)) {
225 		for (cl = gst_encoding_container_profile_get_profiles (GST_ENCODING_CONTAINER_PROFILE (profile)); cl != NULL; cl = cl->next) {
226 			GstEncodingProfile *cp = cl->data;
227 			pcaps = gst_encoding_profile_get_format (cp);
228 			if (gst_caps_can_intersect (caps, pcaps)) {
229 				matches = TRUE;
230 				break;
231 			}
232 		}
233 	}
234 	gst_caps_unref (caps);
235 
236 	return matches;
237 }
238 
239 char *
240 rb_gst_encoding_profile_get_media_type (GstEncodingProfile *profile)
241 {
242 	if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) {
243 		const GList *cl = gst_encoding_container_profile_get_profiles (GST_ENCODING_CONTAINER_PROFILE (profile));
244 		for (; cl != NULL; cl = cl->next) {
245 			GstEncodingProfile *p = cl->data;
246 			if (GST_IS_ENCODING_AUDIO_PROFILE (p)) {
247 				return rb_gst_caps_to_media_type (gst_encoding_profile_get_format (p));
248 			}
249 
250 		}
251 
252 		/* now what? */
253 		return NULL;
254 	} else {
255 		return rb_gst_caps_to_media_type (gst_encoding_profile_get_format (profile));
256 	}
257 }
258 
259 static char *
260 get_encoding_target_file ()
261 {
262 	char *target_file;
263 
264 	target_file = rb_find_user_data_file (ENCODING_TARGET_FILE);
265 	if (g_file_test (target_file, G_FILE_TEST_EXISTS) == FALSE) {
266 		g_free (target_file);
267 		target_file = g_strdup (rb_file (ENCODING_TARGET_FILE));
268 	}
269 
270 	return target_file;
271 }
272 
273 GstEncodingTarget *
274 rb_gst_get_default_encoding_target ()
275 {
276 	if (default_target == NULL) {
277 		char *target_file;
278 		GError *error = NULL;
279 
280 		target_file = get_encoding_target_file ();
281 		default_target = gst_encoding_target_load_from_file (target_file, &error);
282 		if (default_target == NULL) {
283 			g_warning ("Unable to load encoding profiles from %s: %s", target_file, error ? error->message : "no error");
284 			g_clear_error (&error);
285 			g_free (target_file);
286 			return NULL;
287 		}
288 		g_free (target_file);
289 	}
290 
291 	return default_target;
292 }
293 
294 GstEncodingProfile *
295 rb_gst_get_encoding_profile (const char *media_type)
296 {
297 	const GList *l;
298 	GstEncodingTarget *target;
299 	target = rb_gst_get_default_encoding_target ();
300 
301 	for (l = gst_encoding_target_get_profiles (target); l != NULL; l = l->next) {
302 		GstEncodingProfile *profile = l->data;
303 		if (rb_gst_media_type_matches_profile (profile, media_type)) {
304 			gst_encoding_profile_ref (profile);
305 			return profile;
306 		}
307 	}
308 
309 	return NULL;
310 }
311 
312 gboolean
313 rb_gst_media_type_is_lossless (const char *media_type)
314 {
315 	int i;
316 	const char *lossless_types[] = {
317 		"audio/x-flac",
318 		"audio/x-alac",
319 		"audio/x-shorten",
320 		"audio/x-wavpack"	/* not completely sure */
321 	};
322 
323 	for (i = 0; i < G_N_ELEMENTS (lossless_types); i++) {
324 		if (strcmp (media_type, lossless_types[i]) == 0) {
325 			return TRUE;
326 		}
327 	}
328 	return FALSE;
329 }
330 
331 static GstEncodingProfile *
332 get_audio_encoding_profile (GstEncodingProfile *profile)
333 {
334 	if (GST_IS_ENCODING_AUDIO_PROFILE (profile)) {
335 		return profile;
336 	} else if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) {
337 		const GList *l = gst_encoding_container_profile_get_profiles (GST_ENCODING_CONTAINER_PROFILE (profile));
338 		for (; l != NULL; l = l->next) {
339 			GstEncodingProfile *p = get_audio_encoding_profile (l->data);
340 			if (p != NULL) {
341 				return p;
342 			}
343 		}
344 	}
345 
346 	g_warning ("no audio encoding profile in profile %s", gst_encoding_profile_get_name (profile));
347 	return NULL;
348 }
349 
350 static GstElementFactory *
351 get_audio_encoder_factory (GstEncodingProfile *profile)
352 {
353 	GstEncodingProfile *p = get_audio_encoding_profile (profile);
354 	GstElementFactory *f;
355 	GList *l;
356 	GList *fl;
357 
358 	if (p == NULL)
359 		return NULL;
360 
361 	l = gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_ENCODER, GST_RANK_MARGINAL);
362 	fl = gst_element_factory_list_filter (l, gst_encoding_profile_get_format (p), GST_PAD_SRC, FALSE);
363 
364 	if (fl != NULL) {
365 		f = gst_object_ref (fl->data);
366 	} else {
367 		g_warning ("no encoder factory for profile %s", gst_encoding_profile_get_name (p));
368 		f = NULL;
369 	}
370 	gst_plugin_feature_list_free (l);
371 	gst_plugin_feature_list_free (fl);
372 	return f;
373 }
374 
375 /**
376  * rb_gst_encoding_profile_set_preset:
377  * @profile: a #GstEncodingProfile
378  * @preset: preset to apply
379  *
380  * Applies the preset @preset to the audio encoding profile within @profile.
381  */
382 void
383 rb_gst_encoding_profile_set_preset (GstEncodingProfile *profile, const char *preset)
384 {
385 	GstEncodingProfile *p;
386 
387 	p = get_audio_encoding_profile (profile);
388 	if (p != NULL) {
389 		gst_encoding_profile_set_preset (p, preset);
390 	}
391 }
392 
393 /**
394  * rb_gst_encoding_profile_get_settings:
395  * @profile: a #GstEncodingProfile
396  *
397  * Returns a list of settings for the profile @profile that can usefully
398  * be exposed to a user.  This usually means just bitrate/quality settings.
399  * This works by finding the name of the encoder element for the profile
400  * and retrieving a list specific to that encoder.
401  *
402  * Return value: (transfer full) (element-type GParamSpec): list of settings
403  */
404 char **
405 rb_gst_encoding_profile_get_settings (GstEncodingProfile *profile)
406 {
407 	GstElementFactory *factory;
408 	char **setting_names;
409 
410 	factory = get_audio_encoder_factory (profile);
411 	if (factory == NULL) {
412 		return NULL;
413 	}
414 
415 	/* look up list of settings;
416 	 * if we don't have one for the encoder, what do we do?  return everything?
417 	 */
418 	if (target_keyfile == NULL) {
419 		char *file = get_encoding_target_file ();
420 		GError *error = NULL;
421 
422 		target_keyfile = g_key_file_new ();
423 		g_key_file_set_list_separator (target_keyfile, ',');
424 		g_key_file_load_from_file (target_keyfile, file, G_KEY_FILE_NONE, &error);
425 		if (error != NULL) {
426 			g_warning ("Unable to load encoding target keyfile %s: %s", file, error->message);
427 			g_clear_error (&error);
428 		}
429 	}
430 
431 	setting_names = g_key_file_get_string_list (target_keyfile,
432 						    "rhythmbox-encoder-settings",
433 						    gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)),
434 						    NULL,
435 						    NULL);
436 	return setting_names;
437 }
438 
439 GstElement *
440 rb_gst_encoding_profile_get_encoder (GstEncodingProfile *profile)
441 {
442 	GstElementFactory *factory;
443 
444 	factory = get_audio_encoder_factory (profile);
445 	if (factory == NULL) {
446 		return NULL;
447 	}
448 
449 	return gst_element_factory_create (factory, NULL);
450 }
451 
452 char **
453 rb_gst_encoding_profile_get_presets (GstEncodingProfile *profile)
454 {
455 	GstElement *encoder;
456 	char **presets = NULL;
457 
458 	encoder = rb_gst_encoding_profile_get_encoder (profile);
459 	if (encoder != NULL && GST_IS_PRESET (encoder)) {
460 		presets = gst_preset_get_preset_names (GST_PRESET (encoder));
461 		g_object_unref (encoder);
462 	}
463 	return presets;
464 }