static mpc_bool_t
mpc_seek_cb(cb_first_arg, mpc_int32_t offset)
{
	struct mpc_decoder_data *data = (struct mpc_decoder_data *) cb_data;

	return input_stream_lock_seek(data->is, offset, SEEK_SET, NULL);
}
Esempio n. 2
0
static int ogg_seek_cb(void *data, ogg_int64_t offset, int whence)
{
	struct vorbis_input_stream *vis = data;

	return vis->seekable &&
		(!vis->decoder || decoder_get_command(vis->decoder) != DECODE_COMMAND_STOP) &&
		input_stream_lock_seek(vis->input_stream, offset, whence, NULL)
		? 0 : -1;
}
Esempio n. 3
0
static bool mp3_seek(struct mp3_data *data, long offset)
{
	if (!input_stream_lock_seek(data->input_stream, offset, SEEK_SET, NULL))
		return false;

	mad_stream_buffer(&data->stream, data->input_buffer, 0);
	(data->stream).error = 0;

	return true;
}
Esempio n. 4
0
static void
oggflac_decode(struct decoder *decoder, struct input_stream *input_stream)
{
	if (ogg_stream_type_detect(input_stream) != FLAC)
		return;

	/* rewind the stream, because ogg_stream_type_detect() has
	   moved it */
	input_stream_lock_seek(input_stream, 0, SEEK_SET, NULL);

	flac_decode_internal(decoder, input_stream, true);
}
Esempio n. 5
0
static sf_count_t
sndfile_vio_seek(sf_count_t offset, int whence, void *user_data)
{
	struct input_stream *is = user_data;
	bool success;

	success = input_stream_lock_seek(is, offset, whence, NULL);
	if (!success)
		return -1;

	return is->offset;
}
Esempio n. 6
0
static FLAC__StreamDecoderSeekStatus
flac_seek_cb(G_GNUC_UNUSED const FLAC__StreamDecoder *fd,
	     FLAC__uint64 offset, void *fdata)
{
	struct flac_data *data = (struct flac_data *) fdata;

	if (!data->input_stream->seekable)
		return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;

	if (!input_stream_lock_seek(data->input_stream, offset, SEEK_SET,
				    NULL))
		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;

	return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}
Esempio n. 7
0
static void
pcm_stream_decode(struct decoder *decoder, struct input_stream *is)
{
	static const struct audio_format audio_format = {
		.sample_rate = 44100,
		.format = SAMPLE_FORMAT_S16,
		.channels = 2,
	};

	const bool reverse_endian = is->mime != NULL &&
		strcmp(is->mime, "audio/x-mpd-cdda-pcm-reverse") == 0;

	GError *error = NULL;
	enum decoder_command cmd;

	double time_to_size = audio_format_time_to_size(&audio_format);

	float total_time = -1;
	if (is->size >= 0)
		total_time = is->size / time_to_size;

	decoder_initialized(decoder, &audio_format, is->seekable, total_time);

	do {
		char buffer[4096];

		size_t nbytes = decoder_read(decoder, is,
					     buffer, sizeof(buffer));

		if (nbytes == 0 && input_stream_lock_eof(is))
			break;

		if (reverse_endian)
			/* make sure we deliver samples in host byte order */
			reverse_bytes_16((uint16_t *)buffer,
					 (uint16_t *)buffer,
					 (uint16_t *)(buffer + nbytes));

		cmd = nbytes > 0
			? decoder_data(decoder, is,
				       buffer, nbytes, 0)
			: decoder_get_command(decoder);
		if (cmd == DECODE_COMMAND_SEEK) {
			goffset offset = (goffset)(time_to_size *
						   decoder_seek_where(decoder));
			if (input_stream_lock_seek(is, offset, SEEK_SET,
						   &error)) {
				decoder_command_finished(decoder);
			} else {
				g_warning("seeking failed: %s", error->message);
				g_error_free(error);
				decoder_seek_error(decoder);
			}

			cmd = DECODE_COMMAND_NONE;
		}
	} while (cmd == DECODE_COMMAND_NONE);
}

static const char *const pcm_mime_types[] = {
	/* for streams obtained by the cdio_paranoia input plugin */
	"audio/x-mpd-cdda-pcm",

	/* same as above, but with reverse byte order */
	"audio/x-mpd-cdda-pcm-reverse",

	NULL
};

const struct decoder_plugin pcm_decoder_plugin = {
	.name = "pcm",
	.stream_decode = pcm_stream_decode,
	.mime_types = pcm_mime_types,
};
Esempio n. 8
0
/* public */
static void
vorbis_stream_decode(struct decoder *decoder,
		     struct input_stream *input_stream)
{
	GError *error = NULL;
	OggVorbis_File vf;
	struct vorbis_input_stream vis;
	struct audio_format audio_format;
	float total_time;
	int current_section;
	int prev_section = -1;
	long ret;
	char chunk[OGG_CHUNK_SIZE];
	long bitRate = 0;
	long test;
	const vorbis_info *vi;
	enum decoder_command cmd = DECODE_COMMAND_NONE;

	if (ogg_stream_type_detect(input_stream) != VORBIS)
		return;

	/* rewind the stream, because ogg_stream_type_detect() has
	   moved it */
	input_stream_lock_seek(input_stream, 0, SEEK_SET, NULL);

	if (!vorbis_is_open(&vis, &vf, decoder, input_stream))
		return;

	vi = ov_info(&vf, -1);
	if (vi == NULL) {
		g_warning("ov_info() has failed");
		return;
	}

	if (!audio_format_init_checked(&audio_format, vi->rate,
				       SAMPLE_FORMAT_S16,
				       vi->channels, &error)) {
		g_warning("%s", error->message);
		g_error_free(error);
		return;
	}

	total_time = ov_time_total(&vf, -1);
	if (total_time < 0)
		total_time = 0;

	decoder_initialized(decoder, &audio_format, vis.seekable, total_time);

	do {
		if (cmd == DECODE_COMMAND_SEEK) {
			double seek_where = decoder_seek_where(decoder);
			if (0 == ov_time_seek_page(&vf, seek_where)) {
				decoder_command_finished(decoder);
			} else
				decoder_seek_error(decoder);
		}

		ret = ov_read(&vf, chunk, sizeof(chunk),
			      OGG_DECODE_USE_BIGENDIAN, 2, 1, &current_section);
		if (ret == OV_HOLE) /* bad packet */
			ret = 0;
		else if (ret <= 0)
			/* break on EOF or other error */
			break;

		if (current_section != prev_section) {
			char **comments;

			vi = ov_info(&vf, -1);
			if (vi == NULL) {
				g_warning("ov_info() has failed");
				break;
			}

			if (vi->rate != (long)audio_format.sample_rate ||
			    vi->channels != (int)audio_format.channels) {
				/* we don't support audio format
				   change yet */
				g_warning("audio format change, stopping here");
				break;
			}

			comments = ov_comment(&vf, -1)->user_comments;
			vorbis_send_comments(decoder, input_stream, comments);

			struct replay_gain_info rgi;
			if (vorbis_comments_to_replay_gain(&rgi, comments))
				decoder_replay_gain(decoder, &rgi);

			prev_section = current_section;
		}

		if ((test = ov_bitrate_instant(&vf)) > 0)
			bitRate = test / 1000;

		cmd = decoder_data(decoder, input_stream,
				   chunk, ret,
				   bitRate);
	} while (cmd != DECODE_COMMAND_STOP);

	ov_clear(&vf);
}
Esempio n. 9
0
bool
song_file_update(struct song *song)
{
    const char *suffix;
    char *path_fs;
    const struct decoder_plugin *plugin;
    struct stat st;
    struct input_stream *is = NULL;

    assert(song_is_file(song));

    /* check if there's a suffix and a plugin */

    suffix = uri_get_suffix(song->uri);
    if (suffix == NULL)
        return false;

    plugin = decoder_plugin_from_suffix(suffix, NULL);
    if (plugin == NULL)
        return false;

    path_fs = map_song_fs(song);
    if (path_fs == NULL)
        return false;

    if (song->tag != NULL) {
        tag_free(song->tag);
        song->tag = NULL;
    }

    if (stat(path_fs, &st) < 0 || !S_ISREG(st.st_mode)) {
        g_free(path_fs);
        return false;
    }

    song->mtime = st.st_mtime;

    GMutex *mutex = NULL;
    GCond *cond;
#if !GCC_CHECK_VERSION(4, 2)
    /* work around "may be used uninitialized in this function"
       false positive */
    cond = NULL;
#endif

    do {
        /* load file tag */
        song->tag = tag_new();
        if (decoder_plugin_scan_file(plugin, path_fs,
                                     &full_tag_handler, song->tag))
            break;

        tag_free(song->tag);
        song->tag = NULL;

        /* fall back to stream tag */
        if (plugin->scan_stream != NULL) {
            /* open the input_stream (if not already
               open) */
            if (is == NULL) {
                mutex = g_mutex_new();
                cond = g_cond_new();
                is = input_stream_open(path_fs, mutex, cond,
                                       NULL);
            }

            /* now try the stream_tag() method */
            if (is != NULL) {
                song->tag = tag_new();
                if (decoder_plugin_scan_stream(plugin, is,
                                               &full_tag_handler,
                                               song->tag))
                    break;

                tag_free(song->tag);
                song->tag = NULL;

                input_stream_lock_seek(is, 0, SEEK_SET, NULL);
            }
        }

        plugin = decoder_plugin_from_suffix(suffix, plugin);
    } while (plugin != NULL);

    if (is != NULL)
        input_stream_close(is);

    if (mutex != NULL) {
        g_cond_free(cond);
        g_mutex_free(mutex);
    }

    if (song->tag != NULL && tag_is_empty(song->tag))
        tag_scan_fallback(path_fs, &full_tag_handler, song->tag);

    g_free(path_fs);
    return song->tag != NULL;
}
Esempio n. 10
0
/* public */
static void
vorbis_stream_decode(struct decoder *decoder,
		     struct input_stream *input_stream)
{
	GError *error = NULL;

	if (ogg_codec_detect(decoder, input_stream) != OGG_CODEC_VORBIS)
		return;

	/* rewind the stream, because ogg_codec_detect() has
	   moved it */
	input_stream_lock_seek(input_stream, 0, SEEK_SET, NULL);

	struct vorbis_input_stream vis;
	OggVorbis_File vf;
	if (!vorbis_is_open(&vis, &vf, decoder, input_stream))
		return;

	const vorbis_info *vi = ov_info(&vf, -1);
	if (vi == NULL) {
		g_warning("ov_info() has failed");
		return;
	}

	struct audio_format audio_format;
	if (!audio_format_init_checked(&audio_format, vi->rate,
#ifdef HAVE_TREMOR
				       SAMPLE_FORMAT_S16,
#else
				       SAMPLE_FORMAT_FLOAT,
#endif
				       vi->channels, &error)) {
		g_warning("%s", error->message);
		g_error_free(error);
		return;
	}

	float total_time = ov_time_total(&vf, -1);
	if (total_time < 0)
		total_time = 0;

	decoder_initialized(decoder, &audio_format, vis.seekable, total_time);

	enum decoder_command cmd = decoder_get_command(decoder);

#ifdef HAVE_TREMOR
	char buffer[4096];
#else
	float buffer[2048];
	const int frames_per_buffer =
		G_N_ELEMENTS(buffer) / audio_format.channels;
	const unsigned frame_size = sizeof(buffer[0]) * audio_format.channels;
#endif

	int prev_section = -1;
	unsigned kbit_rate = 0;

	do {
		if (cmd == DECODE_COMMAND_SEEK) {
			double seek_where = decoder_seek_where(decoder);
			if (0 == ov_time_seek_page(&vf, seek_where)) {
				decoder_command_finished(decoder);
			} else
				decoder_seek_error(decoder);
		}

		int current_section;

#ifdef HAVE_TREMOR
		long nbytes = ov_read(&vf, buffer, sizeof(buffer),
				      VORBIS_BIG_ENDIAN, 2, 1,
				      &current_section);
#else
		float **per_channel;
		long nframes = ov_read_float(&vf, &per_channel,
					     frames_per_buffer,
					     &current_section);
		long nbytes = nframes;
		if (nframes > 0) {
			vorbis_interleave(buffer,
					  (const float*const*)per_channel,
					  nframes, audio_format.channels);
			nbytes *= frame_size;
		}
#endif

		if (nbytes == OV_HOLE) /* bad packet */
			nbytes = 0;
		else if (nbytes <= 0)
			/* break on EOF or other error */
			break;

		if (current_section != prev_section) {
			vi = ov_info(&vf, -1);
			if (vi == NULL) {
				g_warning("ov_info() has failed");
				break;
			}

			if (vi->rate != (long)audio_format.sample_rate ||
			    vi->channels != (int)audio_format.channels) {
				/* we don't support audio format
				   change yet */
				g_warning("audio format change, stopping here");
				break;
			}

			char **comments = ov_comment(&vf, -1)->user_comments;
			vorbis_send_comments(decoder, input_stream, comments);

			struct replay_gain_info rgi;
			if (vorbis_comments_to_replay_gain(&rgi, comments))
				decoder_replay_gain(decoder, &rgi);

			prev_section = current_section;
		}

		long test = ov_bitrate_instant(&vf);
		if (test > 0)
			kbit_rate = test / 1000;

		cmd = decoder_data(decoder, input_stream,
				   buffer, nbytes,
				   kbit_rate);
	} while (cmd != DECODE_COMMAND_STOP);

	ov_clear(&vf);
}
bool
song_file_update(struct song *song)
{
	const char *suffix;
	char *path_fs;
	const struct decoder_plugin *plugin;
	struct stat st;
	struct input_stream *is = NULL;

	assert(song_is_file(song));

	/* check if there's a suffix and a plugin */

	suffix = uri_get_suffix(song->uri);
	if (suffix == NULL)
		return false;

	plugin = decoder_plugin_from_suffix(suffix, NULL);
	if (plugin == NULL)
		return false;

	path_fs = map_song_fs(song);
	if (path_fs == NULL)
		return false;

	if (song->tag != NULL) {
		tag_free(song->tag);
		song->tag = NULL;
	}

	if (stat(path_fs, &st) < 0 || !S_ISREG(st.st_mode)) {
		g_free(path_fs);
		return false;
	}

	song->mtime = st.st_mtime;

	GMutex *mutex = NULL;
	GCond *cond;

	do {
		/* load file tag */
		song->tag = decoder_plugin_tag_dup(plugin, path_fs);
		if (song->tag != NULL)
			break;

		/* fall back to stream tag */
		if (plugin->stream_tag != NULL) {
			/* open the input_stream (if not already
			   open) */
			if (is == NULL) {
				mutex = g_mutex_new();
				cond = g_cond_new();
				is = input_stream_open(path_fs, mutex, cond,
						       NULL);
			}

			/* now try the stream_tag() method */
			if (is != NULL) {
				song->tag = decoder_plugin_stream_tag(plugin,
								      is);
				if (song->tag != NULL)
					break;

				input_stream_lock_seek(is, 0, SEEK_SET, NULL);
			}
		}

		plugin = decoder_plugin_from_suffix(suffix, plugin);
	} while (plugin != NULL);

	if (is != NULL)
		input_stream_close(is);

	if (mutex != NULL) {
		g_cond_free(cond);
		g_mutex_free(mutex);
	}

	if (song->tag != NULL && tag_is_empty(song->tag))
		song->tag = tag_fallback(path_fs, song->tag);

	g_free(path_fs);
	return song->tag != NULL;
}