XMMS2

src/xmms/segment_plugin.c

Go to the documentation of this file.
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