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 */
27typedef 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
39static gint64 ms_to_samples (gint rate,
40 gint milliseconds);
41
42static gint ms_to_bytes (gint rate,
43 gint64 unit,
44 gint milliseconds);
45
46static gint samples_to_bytes (gint64 unit,
47 gint64 samples);
48
49static gint64 bytes_to_samples (gint64 unit,
50 gint bytes);
51
52
53/*
54 * Function prototypes
55 */
56
57static gboolean xmms_segment_init (xmms_xform_t *xform);
58static void xmms_segment_destroy (xmms_xform_t *xform);
59static gboolean xmms_segment_plugin_setup (xmms_xform_plugin_t *xform_plugin);
60static gint xmms_segment_read (xmms_xform_t *xform,
61 xmms_sample_t *buf,
62 gint len,
63 xmms_error_t *error);
64static gint64 xmms_segment_seek (xmms_xform_t *xform,
65 gint64 samples,
67 xmms_error_t *error);
68
69/*
70 * Plugin header
71 */
72
73static inline gint64
74ms_to_samples (gint rate,
75 gint milliseconds)
76{
77 return (gint64)(((gdouble) rate) * milliseconds / 1000);
78}
79
80static inline gint
81ms_to_bytes (gint rate,
82 gint64 unit,
83 gint milliseconds)
84{
85 return (gint) ms_to_samples (rate, milliseconds) * unit;
86}
87
88static inline gint
89samples_to_bytes (gint64 unit,
90 gint64 samples)
91{
92 return (gint) samples * unit;
93}
94
95static inline gint64
96bytes_to_samples (gint64 unit,
97 gint bytes)
98{
99 return (gint64) bytes / unit;
100}
101
102
103static gboolean
104xmms_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
124static gboolean
125xmms_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;
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
207static void
208xmms_segment_destroy (xmms_xform_t *xform)
209{
211
212 data = xmms_xform_private_data_get (xform);
213 if (data)
214 g_free (data);
215}
216
217static gint
218xmms_segment_read (xmms_xform_t *xform,
219 xmms_sample_t *buf,
220 gint len,
221 xmms_error_t *error)
222{
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
240static gint64
241xmms_segment_seek (xmms_xform_t *xform,
242 gint64 samples,
244 xmms_error_t *error)
245{
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
280 "Segment Effect",
281 XMMS_VERSION,
282 "Handling segment information specified by startms/stopms",
283 xmms_segment_plugin_setup);
284
void xmms_xform_private_data_set(xmms_xform_t *xform, gpointer data)
Set private data for this xform.
Definition xform.c:430
struct xmms_xform_plugin_St xmms_xform_plugin_t
Xform plugin.
gpointer xmms_xform_private_data_get(xmms_xform_t *xform)
Get private data for this xform.
Definition xform.c:424
struct xmms_xform_St xmms_xform_t
void xmms_xform_plugin_indata_add(xmms_xform_plugin_t *plugin,...)
Add a valid input type to the plugin.
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
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
void xmms_xform_plugin_methods_set(xmms_xform_plugin_t *plugin, xmms_xform_methods_t *methods)
Should be called once from the plugin's setupfunc.
void xmms_xform_outdata_type_copy(xmms_xform_t *xform)
Definition xform.c:452
enum xmms_xform_seek_mode_E xmms_xform_seek_mode_t
Seek direction argument.
gint xmms_xform_indata_get_int(xmms_xform_t *xform, xmms_stream_type_key_t key)
Definition xform.c:478
#define XMMS_XFORM_METHODS_INIT(m)
@ XMMS_XFORM_SEEK_SET
struct xmms_segment_data_St xmms_segment_data_t
Methods provided by an xform plugin.
gboolean(* init)(xmms_xform_t *)
Initialisation method.
gint64(* seek)(xmms_xform_t *, gint64, xmms_xform_seek_mode_t, xmms_error_t *)
Seek method.
void(* destroy)(xmms_xform_t *)
Destruction method.
gint(* read)(xmms_xform_t *, gpointer, gint, xmms_error_t *)
Read method.
gboolean xmms_xform_metadata_get_str(xmms_xform_t *xform, const char *key, const gchar **val)
Definition xform.c:580
void xmms_xform_metadata_set_int(xmms_xform_t *xform, const char *key, int val)
Definition xform.c:511
gboolean xmms_xform_metadata_get_int(xmms_xform_t *xform, const char *key, gint32 *val)
Definition xform.c:564
#define xmms_log_info(fmt,...)
Definition xmms_log.h:34
#define XMMS_DBG(fmt,...)
Definition xmms_log.h:32
#define XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION
#define XMMS_MEDIALIB_ENTRY_PROPERTY_STARTMS
#define XMMS_MEDIALIB_ENTRY_PROPERTY_STOPMS
void xmms_sample_t
Definition xmms_sample.h:58
@ XMMS_STREAM_TYPE_MIMETYPE
@ XMMS_STREAM_TYPE_FMT_FORMAT
@ XMMS_STREAM_TYPE_FMT_SAMPLERATE
@ XMMS_STREAM_TYPE_FMT_CHANNELS
@ XMMS_STREAM_TYPE_END
G_BEGIN_DECLS struct xmms_error_St xmms_error_t
#define XMMS_XFORM_BUILTIN(shname, name, ver, desc, setupfunc)
Definition xmms_xform.h:53
@ XMMS_ERROR_INVAL