XMMS2
streamtype.c
Go to the documentation of this file.
1/* XMMS2 - X Music Multiplexer System
2 * Copyright (C) 2003-2011 XMMS2 Team
3 *
4 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 */
16
17/**
18 * @file
19 * xforms
20 */
21
22#include <glib.h>
23
24#include "xmmspriv/xmms_xform.h"
25#include "xmms/xmms_log.h"
26#include "xmms/xmms_object.h"
27
28
29struct xmms_stream_type_St {
30 xmms_object_t obj;
31 gint priority;
32 gchar *name;
33 GList *list;
34};
35
40
41typedef struct xmms_stream_type_val_St {
44 union {
45 char *string;
46 int num;
47 } d;
49
50
51static void
52xmms_stream_type_destroy (xmms_object_t *obj)
53{
55 GList *n;
56
57 g_free (st->name);
58
59 for (n = st->list; n; n = g_list_next (n)) {
60 xmms_stream_type_val_t *val = n->data;
61 if (val->type == STRING) {
62 g_free (val->d.string);
63 }
64 g_free (val);
65 }
66
67 g_list_free (st->list);
68}
69
72{
74
75 res = xmms_object_new (xmms_stream_type_t, xmms_stream_type_destroy);
76 if (!res) {
77 return NULL;
78 }
79
80 res->priority = -1;
81 res->name = NULL;
82
83 for (;;) {
86
87 key = va_arg (ap, int);
88 if (key == XMMS_STREAM_TYPE_END)
89 break;
90
91 if (key == XMMS_STREAM_TYPE_NAME) {
92 res->name = g_strdup (va_arg (ap, char *));
93 continue;
94 }
95
96 if (key == XMMS_STREAM_TYPE_PRIORITY) {
97 res->priority = va_arg (ap, int);
98 continue;
99 }
100
101 val = g_new0 (xmms_stream_type_val_t, 1);
102 val->key = key;
103
104 switch (val->key) {
107 val->type = STRING;
108 val->d.string = g_strdup (va_arg (ap, char *));
109 break;
113 val->type = INT;
114 val->d.num = va_arg (ap, int);
115 break;
116 default:
117 XMMS_DBG ("UNKNOWN TYPE!!");
118 g_free (val);
119 xmms_object_unref (res);
120 return NULL;
121 }
122 res->list = g_list_append (res->list, val);
123 }
124
125 if (!res->name) {
126 const gchar *mime = xmms_stream_type_get_str (res, XMMS_STREAM_TYPE_MIMETYPE);
127 const gchar *url = xmms_stream_type_get_str (res, XMMS_STREAM_TYPE_URL);
128
129 if (mime && url) {
130 res->name = g_strconcat (mime, ":", url, NULL);
131 } else if (mime) {
132 res->name = g_strdup (mime);
133 } else {
134 g_assert_not_reached ();
135 }
136
137 g_strdelimit (res->name, ".", '_');
138 }
139
140 if (res->priority < 0) {
141 res->priority = XMMS_STREAM_TYPE_PRIORITY_DEFAULT;
142 }
143
144 return res;
145}
146
147const char *
149{
150 GList *n;
151
152 if (key == XMMS_STREAM_TYPE_NAME) {
153 return st->name;
154 }
155
156 for (n = st->list; n; n = g_list_next (n)) {
157 xmms_stream_type_val_t *val = n->data;
158 if (val->key == key) {
159 if (val->type != STRING) {
160 XMMS_DBG ("Key passed to get_str is not string");
161 return NULL;
162 }
163 return val->d.string;
164 }
165 }
166 return NULL;
167}
168
169
170gint
172{
173 GList *n;
174
175 if (key == XMMS_STREAM_TYPE_PRIORITY) {
176 return st->priority;
177 }
178
179 for (n = st->list; n; n = g_list_next (n)) {
180 xmms_stream_type_val_t *val = n->data;
181 if (val->key == key) {
182 if (val->type != INT) {
183 XMMS_DBG ("Key passed to get_int is not int");
184 return -1;
185 }
186 return val->d.num;
187 }
188 }
189 return -1;
190}
191
192
193
194
195static gboolean
197{
198 if (vin->type != vout->type)
199 return FALSE;
200 switch (vin->type) {
201 case STRING:
202 return g_pattern_match_simple (vin->d.string, vout->d.string);
203 case INT:
204 return vin->d.num == vout->d.num;
205 }
206 return FALSE;
207}
208
209gboolean
211{
212 GList *in;
213
214 for (in = in_type->list; in; in = g_list_next (in)) {
215 xmms_stream_type_val_t *inval = in->data;
216 GList *n;
217
218 for (n = out_type->list; n; n = g_list_next (n)) {
219 xmms_stream_type_val_t *outval = n->data;
220 if (inval->key == outval->key) {
221 if (!match_val (inval, outval))
222 return FALSE;
223 break;
224 }
225
226 }
227 if (!n) {
228 /* didn't exist in out */
229 return FALSE;
230 }
231 }
232
233 return TRUE;
234}
235
236/**
237 * Find the best pair of formats
238 */
240xmms_stream_type_coerce (const xmms_stream_type_t *in, const GList *goal_types)
241{
242 xmms_stream_type_t *best = NULL;
243 const GList *on;
244/* gint bestscore = GINT_MAX;*/
245 gint bestscore = 100000;
246 gint format, samplerate, channels;
247 gint gformat, gsamplerate, gchannels;
248 const gchar *gmime;
249
253
254 if (format == -1 || samplerate == -1 || channels == -1) {
255 xmms_log_info ("In-type lacks format, samplerate or channels");
256 return NULL;
257 }
258
259 for (on = goal_types ; on; on = g_list_next (on)) {
260 xmms_stream_type_t *goal = on->data;
261 const gchar *mime;
262 gint score = 0;
263
265 if (strcmp (mime, "audio/pcm") != 0) {
266 continue;
267 }
268
272 if (gsamplerate == -1) {
273 gsamplerate = samplerate;
274 }
275 if (gformat == -1 || gchannels == -1) {
276 continue;
277 }
278
279
280 if (gchannels > channels) {
281 /* we loose no quality, just cputime */
282 score += gchannels - channels;
283 } else if (gchannels < channels) {
284 /* quality loss! */
285 score += 10 * (channels - gchannels);
286 }
287
288 /* the format enum should be ordered in
289 quality order */
290 if (gformat > format) {
291 /* we loose no quality, just cputime */
292 score += gformat - format;
293 } else if (gformat < format) {
294 /* quality loss! */
295 score += 10 * (format - gformat);
296 }
297
298
299 if (gsamplerate > samplerate) {
300 /* we loose no quality, just cputime */
301 score += 2 * gsamplerate / samplerate;
302 } else if (gsamplerate < samplerate) {
303 /* quality loss! */
304 score += 20 * samplerate / gsamplerate;
305 }
306
307 if (score < bestscore) {
308 best = goal;
309 bestscore = score;
310 }
311
312 }
313
314 if (!best) {
315 xmms_log_error ("Couldn't convert sample format to any of the %d goal formats",
316 g_list_length ((GList *)goal_types));
317 return NULL;
318 }
319
324
325 /* Use the requested samplerate if target accepts any. */
326 if (gsamplerate == -1) {
327 gsamplerate = samplerate;
328 }
329
336
337 return best;
338}
339
340
341
342/*
343 XMMS_DBG ("Looking for xform with intypes matching:");
344 for (n = prev->out_types; n; n = g_list_next (n)) {
345 xmms_stream_type_val_t *val = n->data;
346 switch (val->type) {
347 case INT:
348 XMMS_DBG (" - %d = %d", val->key, val->d.num);
349 break;
350 case STRING:
351 XMMS_DBG (" - %d = '%s'", val->key, val->d.string);
352 break;
353 default:
354 XMMS_DBG (" - ????");
355 break;
356 }
357 }
358
359*/
360
362_xmms_stream_type_new (const gchar *begin, ...)
363{
365 va_list ap;
366
367 va_start (ap, begin);
368 res = xmms_stream_type_parse (ap);
369 va_end (ap);
370
371 return res;
372}
const char * xmms_stream_type_get_str(const xmms_stream_type_t *st, xmms_stream_type_key_t key)
Definition: streamtype.c:148
struct xmms_stream_type_val_St xmms_stream_type_val_t
enum xmms_stream_type_val_type_E xmms_stream_type_val_type_t
gboolean xmms_stream_type_match(const xmms_stream_type_t *in_type, const xmms_stream_type_t *out_type)
Definition: streamtype.c:210
xmms_stream_type_t * _xmms_stream_type_new(const gchar *begin,...)
Definition: streamtype.c:362
gint xmms_stream_type_get_int(const xmms_stream_type_t *st, xmms_stream_type_key_t key)
Definition: streamtype.c:171
xmms_stream_type_t * xmms_stream_type_parse(va_list ap)
Definition: streamtype.c:71
xmms_stream_type_val_type_E
Definition: streamtype.c:36
@ STRING
Definition: streamtype.c:37
@ INT
Definition: streamtype.c:38
xmms_stream_type_t * xmms_stream_type_coerce(const xmms_stream_type_t *in, const GList *goal_types)
Find the best pair of formats.
Definition: streamtype.c:240
#define xmms_log_error(fmt,...)
Definition: xmms_log.h:35
#define xmms_log_info(fmt,...)
Definition: xmms_log.h:34
#define XMMS_DBG(fmt,...)
Definition: xmms_log.h:32
#define XMMS_STREAM_TYPE_PRIORITY_DEFAULT
#define XMMS_STREAM_TYPE_BEGIN
@ XMMS_STREAM_TYPE_MIMETYPE
@ XMMS_STREAM_TYPE_FMT_FORMAT
@ XMMS_STREAM_TYPE_NAME
@ XMMS_STREAM_TYPE_FMT_SAMPLERATE
@ XMMS_STREAM_TYPE_FMT_CHANNELS
@ XMMS_STREAM_TYPE_PRIORITY
@ XMMS_STREAM_TYPE_URL
@ XMMS_STREAM_TYPE_END
enum xmms_stream_type_key_E xmms_stream_type_key_t
struct xmms_stream_type_St xmms_stream_type_t
#define xmms_object_new(objtype, destroyfunc)
Definition: xmms_object.h:115
#define xmms_object_unref(obj)
Definition: xmms_object.h:109