00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <stdlib.h>
00018 #include <string.h>
00019 #include "xmms/xmms_sample.h"
00020 #include "xmmspriv/xmms_xform.h"
00021 #include "xmms/xmms_log.h"
00022 #include "xmms/xmms_error.h"
00023
00024
00025
00026
00027 typedef struct xmms_segment_data_St {
00028 gint64 start_bytes;
00029 gint64 current_bytes;
00030 gint64 stop_bytes;
00031 gint64 unit;
00032 } xmms_segment_data_t;
00033
00034
00035
00036
00037
00038
00039 static gint64 ms_to_samples (gint rate,
00040 gint milliseconds);
00041
00042 static gint ms_to_bytes (gint rate,
00043 gint64 unit,
00044 gint milliseconds);
00045
00046 static gint samples_to_bytes (gint64 unit,
00047 gint64 samples);
00048
00049 static gint64 bytes_to_samples (gint64 unit,
00050 gint bytes);
00051
00052
00053
00054
00055
00056
00057 static gboolean xmms_segment_init (xmms_xform_t *xform);
00058 static void xmms_segment_destroy (xmms_xform_t *xform);
00059 static gboolean xmms_segment_plugin_setup (xmms_xform_plugin_t *xform_plugin);
00060 static gint xmms_segment_read (xmms_xform_t *xform,
00061 xmms_sample_t *buf,
00062 gint len,
00063 xmms_error_t *error);
00064 static gint64 xmms_segment_seek (xmms_xform_t *xform,
00065 gint64 samples,
00066 xmms_xform_seek_mode_t whence,
00067 xmms_error_t *error);
00068
00069
00070
00071
00072
00073 static inline gint64
00074 ms_to_samples (gint rate,
00075 gint milliseconds)
00076 {
00077 return (gint64)(((gdouble) rate) * milliseconds / 1000);
00078 }
00079
00080 static inline gint
00081 ms_to_bytes (gint rate,
00082 gint64 unit,
00083 gint milliseconds)
00084 {
00085 return (gint) ms_to_samples (rate, milliseconds) * unit;
00086 }
00087
00088 static inline gint
00089 samples_to_bytes (gint64 unit,
00090 gint64 samples)
00091 {
00092 return (gint) samples * unit;
00093 }
00094
00095 static inline gint64
00096 bytes_to_samples (gint64 unit,
00097 gint bytes)
00098 {
00099 return (gint64) bytes / unit;
00100 }
00101
00102
00103 static gboolean
00104 xmms_segment_plugin_setup (xmms_xform_plugin_t *xform_plugin)
00105 {
00106 xmms_xform_methods_t methods;
00107
00108 XMMS_XFORM_METHODS_INIT (methods);
00109 methods.init = xmms_segment_init;
00110 methods.destroy = xmms_segment_destroy;
00111 methods.read = xmms_segment_read;
00112 methods.seek = xmms_segment_seek;
00113
00114 xmms_xform_plugin_methods_set (xform_plugin, &methods);
00115
00116 xmms_xform_plugin_indata_add (xform_plugin,
00117 XMMS_STREAM_TYPE_MIMETYPE,
00118 "audio/pcm",
00119 XMMS_STREAM_TYPE_END);
00120
00121 return TRUE;
00122 }
00123
00124 static gboolean
00125 xmms_segment_init (xmms_xform_t *xform)
00126 {
00127 const gchar *nptr;
00128 char *endptr;
00129 gint startms;
00130 gint stopms;
00131 const gchar *metakey;
00132 xmms_error_t *error;
00133 xmms_segment_data_t *data;
00134 gint fmt;
00135 gint channels;
00136 gint samplerate;
00137 gint sample_size_in_bytes;
00138 gint64 samples;
00139
00140 g_return_val_if_fail (xform, FALSE);
00141
00142 xmms_xform_outdata_type_copy (xform);
00143
00144
00145 metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_STARTMS;
00146 if (!xmms_xform_metadata_get_str (xform, metakey, &nptr)) {
00147 return TRUE;
00148 }
00149
00150 startms = (gint) strtol (nptr, &endptr, 10);
00151 if (*endptr != '\0') {
00152 XMMS_DBG ("\"startms\" has garbage!");
00153 return TRUE;
00154 }
00155
00156
00157 metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_STOPMS;
00158 if (xmms_xform_metadata_get_str (xform, metakey, &nptr)) {
00159 stopms = (gint) strtol (nptr, &endptr, 10);
00160 if (*endptr != '\0') {
00161 xmms_log_info ("\"stopms\" has garbage, ignoring");
00162 stopms = INT_MAX;
00163 }
00164 } else {
00165
00166 metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION;
00167 if (!xmms_xform_metadata_get_int (xform, metakey, &stopms)) {
00168 XMMS_DBG ("\"duration\" doesnt exist, ignore stopms.");
00169
00170 stopms = INT_MAX;
00171 }
00172 }
00173
00174
00175 if (stopms != INT_MAX) {
00176 metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION;
00177 xmms_xform_metadata_set_int (xform, metakey, stopms - startms);
00178 }
00179
00180
00181 channels = xmms_xform_indata_get_int (xform, XMMS_STREAM_TYPE_FMT_CHANNELS);
00182 fmt = xmms_xform_indata_get_int (xform, XMMS_STREAM_TYPE_FMT_FORMAT);
00183 samplerate = xmms_xform_indata_get_int (xform, XMMS_STREAM_TYPE_FMT_SAMPLERATE);
00184
00185 sample_size_in_bytes = xmms_sample_size_get (fmt);
00186
00187
00188 data = g_new0 (xmms_segment_data_t, 1);
00189 data->unit = channels * sample_size_in_bytes;
00190 data->current_bytes = data->start_bytes = ms_to_bytes (samplerate,
00191 data->unit,
00192 startms);
00193 data->stop_bytes = ms_to_bytes (samplerate,
00194 data->unit,
00195 stopms);
00196
00197 xmms_xform_private_data_set (xform, data);
00198
00199
00200
00201 samples = ms_to_samples (samplerate, startms);
00202 xmms_xform_seek (xform, samples, XMMS_XFORM_SEEK_SET, error);
00203
00204 return TRUE;
00205 }
00206
00207 static void
00208 xmms_segment_destroy (xmms_xform_t *xform)
00209 {
00210 xmms_segment_data_t *data;
00211
00212 data = xmms_xform_private_data_get (xform);
00213 if (data)
00214 g_free (data);
00215 }
00216
00217 static gint
00218 xmms_segment_read (xmms_xform_t *xform,
00219 xmms_sample_t *buf,
00220 gint len,
00221 xmms_error_t *error)
00222 {
00223 xmms_segment_data_t *data;
00224 gint res;
00225
00226 data = xmms_xform_private_data_get (xform);
00227
00228 if (data && (data->current_bytes + len >= data->stop_bytes)) {
00229 len = data->stop_bytes - data->current_bytes;
00230 }
00231
00232 res = xmms_xform_read (xform, buf, len, error);
00233 if (data && (res > 0)) {
00234 data->current_bytes += res;
00235 }
00236
00237 return res;
00238 }
00239
00240 static gint64
00241 xmms_segment_seek (xmms_xform_t *xform,
00242 gint64 samples,
00243 xmms_xform_seek_mode_t whence,
00244 xmms_error_t *error)
00245 {
00246 xmms_segment_data_t *data;
00247 gint64 res;
00248 gint64 tmp;
00249
00250 data = xmms_xform_private_data_get (xform);
00251
00252 if (!data) {
00253 return xmms_xform_seek (xform, samples, whence, error);
00254 }
00255
00256 g_return_val_if_fail (whence == XMMS_XFORM_SEEK_SET, -1);
00257
00258 if (samples < 0 ||
00259 samples > bytes_to_samples (data->unit,
00260 data->stop_bytes
00261 - data->start_bytes)) {
00262 xmms_error_set (error,
00263 XMMS_ERROR_INVAL,
00264 "Seeking out of range");
00265 return -1;
00266 }
00267
00268 tmp = bytes_to_samples (data->unit,
00269 data->start_bytes);
00270 res = xmms_xform_seek (xform,
00271 samples + tmp,
00272 whence,
00273 error);
00274 data->current_bytes = samples_to_bytes (data->unit,
00275 res);
00276 return res - tmp;
00277 }
00278
00279 XMMS_XFORM_BUILTIN (segment,
00280 "Segment Effect",
00281 XMMS_VERSION,
00282 "Handling segment information specified by startms/stopms",
00283 xmms_segment_plugin_setup);
00284