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 
29 struct xmms_stream_type_St {
30  xmms_object_t obj;
31  gint priority;
32  gchar *name;
33  GList *list;
34 };
35 
38  INT,
40 
41 typedef struct xmms_stream_type_val_St {
44  union {
45  char *string;
46  int num;
47  } d;
49 
50 
51 static void
52 xmms_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 {
73  xmms_stream_type_t *res;
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 
147 const 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 
170 gint
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 
195 static gboolean
196 match_val (xmms_stream_type_val_t *vin, xmms_stream_type_val_t *vout)
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 
209 gboolean
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  */
240 xmms_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 
334  XMMS_STREAM_TYPE_FMT_SAMPLERATE, gsamplerate,
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 {
364  xmms_stream_type_t *res;
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 }
enum xmms_stream_type_key_E xmms_stream_type_key_t
gint xmms_stream_type_get_int(const xmms_stream_type_t *st, xmms_stream_type_key_t key)
Definition: streamtype.c:171
#define xmms_object_unref(obj)
Definition: xmms_object.h:109
struct xmms_stream_type_St xmms_stream_type_t
xmms_stream_type_val_type_E
Definition: streamtype.c:36
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
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
#define xmms_log_error(fmt,...)
Definition: xmms_log.h:35
#define XMMS_STREAM_TYPE_BEGIN
enum xmms_stream_type_val_type_E xmms_stream_type_val_type_t
Definition: streamtype.c:38
#define xmms_log_info(fmt,...)
Definition: xmms_log.h:34
#define XMMS_STREAM_TYPE_PRIORITY_DEFAULT
#define XMMS_DBG(fmt,...)
Definition: xmms_log.h:32
#define xmms_object_new(objtype, destroyfunc)
Definition: xmms_object.h:115
const char * xmms_stream_type_get_str(const xmms_stream_type_t *st, xmms_stream_type_key_t key)
Definition: streamtype.c:148
xmms_stream_type_t * xmms_stream_type_parse(va_list ap)
Definition: streamtype.c:71
struct xmms_stream_type_val_St xmms_stream_type_val_t