XMMS2
segment_plugin.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 #include <stdlib.h>
18 #include <string.h>
19 #include "xmms/xmms_sample.h"
20 #include "xmmspriv/xmms_xform.h"
21 #include "xmms/xmms_log.h"
22 #include "xmms/xmms_error.h"
23 
24 /*
25  * Data structure
26  */
27 typedef struct xmms_segment_data_St {
28  gint64 start_bytes;
29  gint64 current_bytes;
30  gint64 stop_bytes;
31  gint64 unit; /* channels * sample_size_in_bytes */
33 
34 
35 /*
36  * Helper functions
37  */
38 
39 static gint64 ms_to_samples (gint rate,
40  gint milliseconds);
41 
42 static gint ms_to_bytes (gint rate,
43  gint64 unit,
44  gint milliseconds);
45 
46 static gint samples_to_bytes (gint64 unit,
47  gint64 samples);
48 
49 static gint64 bytes_to_samples (gint64 unit,
50  gint bytes);
51 
52 
53 /*
54  * Function prototypes
55  */
56 
57 static gboolean xmms_segment_init (xmms_xform_t *xform);
58 static void xmms_segment_destroy (xmms_xform_t *xform);
59 static gboolean xmms_segment_plugin_setup (xmms_xform_plugin_t *xform_plugin);
60 static gint xmms_segment_read (xmms_xform_t *xform,
61  xmms_sample_t *buf,
62  gint len,
63  xmms_error_t *error);
64 static gint64 xmms_segment_seek (xmms_xform_t *xform,
65  gint64 samples,
67  xmms_error_t *error);
68 
69 /*
70  * Plugin header
71  */
72 
73 static inline gint64
74 ms_to_samples (gint rate,
75  gint milliseconds)
76 {
77  return (gint64)(((gdouble) rate) * milliseconds / 1000);
78 }
79 
80 static inline gint
81 ms_to_bytes (gint rate,
82  gint64 unit,
83  gint milliseconds)
84 {
85  return (gint) ms_to_samples (rate, milliseconds) * unit;
86 }
87 
88 static inline gint
89 samples_to_bytes (gint64 unit,
90  gint64 samples)
91 {
92  return (gint) samples * unit;
93 }
94 
95 static inline gint64
96 bytes_to_samples (gint64 unit,
97  gint bytes)
98 {
99  return (gint64) bytes / unit;
100 }
101 
102 
103 static gboolean
104 xmms_segment_plugin_setup (xmms_xform_plugin_t *xform_plugin)
105 {
106  xmms_xform_methods_t methods;
107 
108  XMMS_XFORM_METHODS_INIT (methods);
109  methods.init = xmms_segment_init;
110  methods.destroy = xmms_segment_destroy;
111  methods.read = xmms_segment_read;
112  methods.seek = xmms_segment_seek;
113 
114  xmms_xform_plugin_methods_set (xform_plugin, &methods);
115 
116  xmms_xform_plugin_indata_add (xform_plugin,
118  "audio/pcm",
120 
121  return TRUE;
122 }
123 
124 static gboolean
125 xmms_segment_init (xmms_xform_t *xform)
126 {
127  const gchar *nptr;
128  char *endptr;
129  gint startms;
130  gint stopms;
131  const gchar *metakey;
132  xmms_error_t error;
133  xmms_segment_data_t *data;
134  gint fmt;
135  gint channels;
136  gint samplerate;
137  gint sample_size_in_bytes;
138  gint64 samples;
139 
140  g_return_val_if_fail (xform, FALSE);
141 
143 
144  /* get startms */
146  if (!xmms_xform_metadata_get_str (xform, metakey, &nptr)) {
147  return TRUE;
148  }
149 
150  startms = (gint) strtol (nptr, &endptr, 10);
151  if (*endptr != '\0') {
152  XMMS_DBG ("\"startms\" has garbage!");
153  return TRUE;
154  }
155 
156  /* get stopms */
158  if (xmms_xform_metadata_get_str (xform, metakey, &nptr)) {
159  stopms = (gint) strtol (nptr, &endptr, 10);
160  if (*endptr != '\0') {
161  xmms_log_info ("\"stopms\" has garbage, ignoring");
162  stopms = INT_MAX;
163  }
164  } else {
165  /* This is the last track, stopms is the playback duration */
167  if (!xmms_xform_metadata_get_int (xform, metakey, &stopms)) {
168  XMMS_DBG ("\"duration\" doesnt exist, ignore stopms.");
169  /* ignore stopms by setting it to the maximum value */
170  stopms = INT_MAX;
171  }
172  }
173 
174  /* set the correct duration */
175  if (stopms != INT_MAX) {
177  xmms_xform_metadata_set_int (xform, metakey, stopms - startms);
178  }
179 
180  /* some calculation */
184 
185  sample_size_in_bytes = xmms_sample_size_get (fmt);
186 
187  /* allocate and set data */
188  data = g_new0 (xmms_segment_data_t, 1);
189  data->unit = channels * sample_size_in_bytes;
190  data->current_bytes = data->start_bytes = ms_to_bytes (samplerate,
191  data->unit,
192  startms);
193  data->stop_bytes = ms_to_bytes (samplerate,
194  data->unit,
195  stopms);
196 
197  xmms_xform_private_data_set (xform, data);
198 
199  /* Now seek to startms */
200 
201  samples = ms_to_samples (samplerate, startms);
202  xmms_xform_seek (xform, samples, XMMS_XFORM_SEEK_SET, &error);
203 
204  return TRUE;
205 }
206 
207 static void
208 xmms_segment_destroy (xmms_xform_t *xform)
209 {
210  xmms_segment_data_t *data;
211 
212  data = xmms_xform_private_data_get (xform);
213  if (data)
214  g_free (data);
215 }
216 
217 static gint
218 xmms_segment_read (xmms_xform_t *xform,
219  xmms_sample_t *buf,
220  gint len,
221  xmms_error_t *error)
222 {
223  xmms_segment_data_t *data;
224  gint res;
225 
226  data = xmms_xform_private_data_get (xform);
227 
228  if (data && (data->current_bytes + len >= data->stop_bytes)) {
229  len = data->stop_bytes - data->current_bytes;
230  }
231 
232  res = xmms_xform_read (xform, buf, len, error);
233  if (data && (res > 0)) {
234  data->current_bytes += res;
235  }
236 
237  return res;
238 }
239 
240 static gint64
241 xmms_segment_seek (xmms_xform_t *xform,
242  gint64 samples,
243  xmms_xform_seek_mode_t whence,
244  xmms_error_t *error)
245 {
246  xmms_segment_data_t *data;
247  gint64 res;
248  gint64 tmp;
249 
250  data = xmms_xform_private_data_get (xform);
251 
252  if (!data) {
253  return xmms_xform_seek (xform, samples, whence, error);
254  }
255 
256  g_return_val_if_fail (whence == XMMS_XFORM_SEEK_SET, -1);
257 
258  if (samples < 0 ||
259  samples > bytes_to_samples (data->unit,
260  data->stop_bytes
261  - data->start_bytes)) {
262  xmms_error_set (error,
264  "Seeking out of range");
265  return -1;
266  }
267 
268  tmp = bytes_to_samples (data->unit,
269  data->start_bytes);
270  res = xmms_xform_seek (xform,
271  samples + tmp,
272  whence,
273  error);
274  data->current_bytes = samples_to_bytes (data->unit,
275  res);
276  return res - tmp;
277 }
278 
279 XMMS_XFORM_BUILTIN (segment,
280  "Segment Effect",
281  XMMS_VERSION,
282  "Handling segment information specified by startms/stopms",
283  xmms_segment_plugin_setup);
284 
struct xmms_xform_plugin_St xmms_xform_plugin_t
Xform plugin.
#define XMMS_MEDIALIB_ENTRY_PROPERTY_STARTMS
Definition: xmms_medialib.h:65
void xmms_xform_plugin_indata_add(xmms_xform_plugin_t *plugin,...)
Add a valid input type to the plugin.
Definition: xform_plugin.c:79
struct xmms_xform_St xmms_xform_t
gboolean(* init)(xmms_xform_t *)
Initialisation method.
XMMS_XFORM_BUILTIN(segment, "Segment Effect", XMMS_VERSION, "Handling segment information specified by startms/stopms", xmms_segment_plugin_setup)
#define XMMS_MEDIALIB_ENTRY_PROPERTY_STOPMS
Definition: xmms_medialib.h:66
gpointer xmms_xform_private_data_get(xmms_xform_t *xform)
Get private data for this xform.
Definition: xform.c:424
void xmms_xform_metadata_set_int(xmms_xform_t *xform, const char *key, int val)
Definition: xform.c:511
void xmms_sample_t
Definition: xmms_sample.h:58
enum xmms_xform_seek_mode_E xmms_xform_seek_mode_t
Seek direction argument.
Methods provided by an xform plugin.
void xmms_xform_plugin_methods_set(xmms_xform_plugin_t *plugin, xmms_xform_methods_t *methods)
Should be called once from the plugin&#39;s setupfunc.
Definition: xform_plugin.c:53
gint64 xmms_xform_seek(xmms_xform_t *xform, gint64 offset, xmms_xform_seek_mode_t whence, xmms_error_t *err)
Change offset in stream.
Definition: xform.c:1120
void(* destroy)(xmms_xform_t *)
Destruction method.
#define xmms_log_info(fmt,...)
Definition: xmms_log.h:34
void xmms_xform_outdata_type_copy(xmms_xform_t *xform)
Definition: xform.c:452
gboolean xmms_xform_metadata_get_int(xmms_xform_t *xform, const char *key, gint32 *val)
Definition: xform.c:564
gint xmms_xform_read(xmms_xform_t *xform, gpointer buf, gint siz, xmms_error_t *err)
Read data from previous xform.
Definition: xform.c:1113
gint(* read)(xmms_xform_t *, gpointer, gint, xmms_error_t *)
Read method.
#define XMMS_DBG(fmt,...)
Definition: xmms_log.h:32
gint xmms_xform_indata_get_int(xmms_xform_t *xform, xmms_stream_type_key_t key)
Definition: xform.c:478
G_BEGIN_DECLS struct xmms_error_St xmms_error_t
#define XMMS_XFORM_METHODS_INIT(m)
void xmms_xform_private_data_set(xmms_xform_t *xform, gpointer data)
Set private data for this xform.
Definition: xform.c:430
struct xmms_segment_data_St xmms_segment_data_t
gint64(* seek)(xmms_xform_t *, gint64, xmms_xform_seek_mode_t, xmms_error_t *)
Seek method.
gboolean xmms_xform_metadata_get_str(xmms_xform_t *xform, const char *key, const gchar **val)
Definition: xform.c:580
#define XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION
Definition: xmms_medialib.h:39