No issues found
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 |
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 }