XMMS2
|
00001 /* XMMS2 - X Music Multiplexer System 00002 * Copyright (C) 2003-2009 XMMS2 Team 00003 * 00004 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!! 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 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 * Data structure 00026 */ 00027 typedef struct xmms_segment_data_St { 00028 gint64 start_bytes; 00029 gint64 current_bytes; 00030 gint64 stop_bytes; 00031 gint64 unit; /* channels * sample_size_in_bytes */ 00032 } xmms_segment_data_t; 00033 00034 00035 /* 00036 * Helper functions 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 * Function prototypes 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 * Plugin header 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 /* get startms */ 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 /* get stopms */ 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 /* This is the last track, stopms is the playback duration */ 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 /* ignore stopms by setting it to the maximum value */ 00170 stopms = INT_MAX; 00171 } 00172 } 00173 00174 /* set the correct duration */ 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 /* some calculation */ 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 /* allocate and set data */ 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 /* Now seek to startms */ 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