static uint32_t wavpack_get_pos (void *id) { xmms_xform_t *xform = id; xmms_wavpack_data_t *data; xmms_error_t error; g_return_val_if_fail (xform, (uint32_t)-1); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, (uint32_t)-1); gint64 pos = xmms_xform_seek (xform, 0, XMMS_XFORM_SEEK_CUR, &error); if (data->pushback_set) { /* we didn't actually perform the pushback on the underlying stream so adjust offset accordingly */ pos--; } return (uint32_t)pos; }
static gint64 xmms_mad_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err) { xmms_mad_data_t *data; guint bytes; gint64 res; g_return_val_if_fail (whence == XMMS_XFORM_SEEK_SET, -1); g_return_val_if_fail (xform, -1); data = xmms_xform_private_data_get (xform); if (data->xing && xmms_xing_has_flag (data->xing, XMMS_XING_FRAMES) && xmms_xing_has_flag (data->xing, XMMS_XING_TOC)) { guint i; i = (guint) (100ULL * samples / xmms_xing_get_frames (data->xing) / 1152); bytes = xmms_xing_get_toc (data->xing, i) * (xmms_xing_get_bytes (data->xing) / 256); } else { bytes = (guint)(((gdouble)samples) * data->bitrate / data->samplerate) / 8; } XMMS_DBG ("Try seek %" G_GINT64_FORMAT " samples -> %d bytes", samples, bytes); res = xmms_xform_seek (xform, bytes, XMMS_XFORM_SEEK_SET, err); if (res == -1) { return -1; } /* we don't have sample accuracy when seeking, so there is no use trying */ data->samples_to_skip = 0; data->samples_to_play = -1; return samples; }
static uint32_t xmms_mp4_seek_callback (void *user_data, uint64_t position) { xmms_xform_t *xform; xmms_mp4_data_t *data; xmms_error_t error; gint ret = 0; g_return_val_if_fail (user_data, -1); xform = user_data; data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, -1); ret = xmms_xform_seek (xform, position, XMMS_XFORM_SEEK_SET, &error); /* If seeking was successfull, flush the internal buffer */ if (ret >= 0) { data->buffer_length = 0; } return ret; }
static int opus_callback_seek (void *datasource, opus_int64 offset, int whence) { xmms_xform_t *xform = datasource; xmms_error_t err; gint ret; g_return_val_if_fail (xform, -1); xmms_error_reset (&err); if (whence == SEEK_CUR) { whence = XMMS_XFORM_SEEK_CUR; } else if (whence == SEEK_SET) { whence = XMMS_XFORM_SEEK_SET; } else if (whence == SEEK_END) { whence = XMMS_XFORM_SEEK_END; } ret = xmms_xform_seek (xform, (gint64) offset, whence, &err); return (ret == -1) ? -1 : 0; }
/* return 0 on success, -1 on error */ static int wavpack_set_pos_abs (void *id, uint32_t pos) { xmms_xform_t *xform = id; xmms_wavpack_data_t *data; xmms_error_t error; gint ret; g_return_val_if_fail (xform, -1); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, -1); ret = xmms_xform_seek (xform, pos, XMMS_XFORM_SEEK_SET, &error); if (ret == -1) { return -1; } data->pushback_set = FALSE; return 0; }
static gboolean xmms_mp4_init (xmms_xform_t *xform) { xmms_mp4_data_t *data; xmms_error_t error; gint bytes_read; guchar *tmpbuf; guint tmpbuflen; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_mp4_data_t, 1); data->outbuf = g_string_new (NULL); data->buffer_size = MP4_BUFFER_SIZE; xmms_xform_private_data_set (xform, data); data->sampleid = 1; data->numsamples = 0; bytes_read = xmms_xform_read (xform, (gchar *) data->buffer + data->buffer_length, data->buffer_size - data->buffer_length, &error); data->buffer_length += bytes_read; if (bytes_read < 8) { XMMS_DBG ("Not enough bytes to check the MP4 header"); goto err; } /* * MP4 not supported (yet) on non-seekable transport * this needs little tweaking in mp4ff at least */ if (xmms_xform_seek (xform, 0, XMMS_XFORM_SEEK_CUR, &error) < 0) { XMMS_DBG ("Non-seekable transport on MP4 not yet supported"); goto err; } data->mp4ff_cb = g_new0 (mp4ff_callback_t, 1); data->mp4ff_cb->read = xmms_mp4_read_callback; data->mp4ff_cb->seek = xmms_mp4_seek_callback; data->mp4ff_cb->user_data = xform; data->mp4ff = mp4ff_open_read (data->mp4ff_cb); if (!data->mp4ff) { XMMS_DBG ("Error opening mp4 demuxer\n"); goto err;; } data->track = xmms_mp4_get_track (xform, data->mp4ff); if (data->track < 0) { XMMS_DBG ("Can't find suitable audio track from MP4 file\n"); goto err; } data->numsamples = mp4ff_num_samples (data->mp4ff, data->track); mp4ff_get_decoder_config (data->mp4ff, data->track, &tmpbuf, &tmpbuflen); xmms_xform_auxdata_set_bin (xform, "decoder_config", tmpbuf, tmpbuflen); g_free (tmpbuf); xmms_mp4_get_mediainfo (xform); XMMS_DBG ("MP4 demuxer inited successfully!"); return TRUE; err: g_free (data->mp4ff_cb); g_string_free (data->outbuf, TRUE); g_free (data); return FALSE; }
static gint64 xmms_vocoder_seek (xmms_xform_t *xform, gint64 offset, xmms_xform_seek_mode_t whence, xmms_error_t *err) { return xmms_xform_seek (xform, offset, whence, err); }
static gboolean xmms_apetag_read (xmms_xform_t *xform) { guchar buffer[32], *tagdata; xmms_error_t error; guint version, tag_size, items, flags; gint64 tag_position; gint pos, i, ret; g_return_val_if_fail (xform, FALSE); /* Try to find the 32-byte footer from the end of file */ tag_position = xmms_xform_seek (xform, -32, XMMS_XFORM_SEEK_END, &error); if (tag_position < 0) { /* Seeking failed, failed to read tags */ return FALSE; } /* Read footer data if seeking was possible */ ret = xmms_xform_read (xform, buffer, 32, &error); if (ret != 32) { xmms_log_error ("Failed to read APE tag footer"); return FALSE; } /* Check that the footer is valid, if not continue searching */ if (memcmp (buffer, "APETAGEX", 8)) { /* Try to find the 32-byte footer before 128-byte ID3v1 tag */ tag_position = xmms_xform_seek (xform, -160, XMMS_XFORM_SEEK_END, &error); if (tag_position < 0) { /* Seeking failed, failed to read tags */ xmms_log_error ("Failed to seek to APE tag footer"); return FALSE; } /* Read footer data if seeking was possible */ ret = xmms_xform_read (xform, buffer, 32, &error); if (ret != 32) { xmms_log_error ("Failed to read APE tag footer"); return FALSE; } if (memcmp (buffer, "APETAGEX", 8)) { /* Didn't find any APE tag from the file */ return FALSE; } } version = xmms_apetag_get_le32 (buffer + 8); tag_size = xmms_apetag_get_le32 (buffer + 12); items = xmms_apetag_get_le32 (buffer + 16); flags = xmms_apetag_get_le32 (buffer + 20); if (flags & APE_TAG_FLAG_IS_HEADER) { /* We need a footer, not a header... */ return FALSE; } if (version != 1000 && version != 2000) { xmms_log_error ("Invalid tag version, the writer is probably corrupted!"); return FALSE; } /* Seek to the beginning of the actual tag data */ ret = xmms_xform_seek (xform, tag_position - tag_size + 32, XMMS_XFORM_SEEK_SET, &error); if (ret < 0) { xmms_log_error ("Couldn't seek to the tag starting position, returned %d", ret); return FALSE; } tagdata = g_malloc (tag_size); ret = xmms_xform_read (xform, tagdata, tag_size, &error); if (ret != tag_size) { xmms_log_error ("Couldn't read the tag data, returned %d", ret); g_free (tagdata); return FALSE; } pos = 0; for (i = 0; i < items; i++) { gint itemlen, flags; gchar *key, *item; itemlen = xmms_apetag_get_le32 (tagdata + pos); pos += 4; flags = xmms_apetag_get_le32 (tagdata + pos); pos += 4; key = (gchar *) tagdata + pos; pos += strlen (key) + 1; switch (flags & APE_TAG_FLAG_DATA_TYPE) { case APE_TAG_DATA_TYPE_UTF8: item = g_strndup ((gchar *) tagdata + pos, itemlen); break; case APE_TAG_DATA_TYPE_BINARY: item = g_malloc (itemlen); memcpy (item, tagdata + pos, itemlen); break; case APE_TAG_DATA_TYPE_LOCATOR: item = NULL; break; } if (item != NULL && !xmms_xform_metadata_mapper_match (xform, key, item, itemlen)) { if ((flags & APE_TAG_FLAG_DATA_TYPE) == APE_TAG_DATA_TYPE_UTF8) { XMMS_DBG ("Unhandled tag '%s' = '%s'", key, item); } else { XMMS_DBG ("Unhandled tag '%s' = '(binary)'", key); } } g_free (item); pos += itemlen; } g_free (tagdata); return TRUE; }
static gint64 xmms_xml_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err) { return xmms_xform_seek (xform, samples, whence, err); }