static FLAC__bool flac_eof_cb(G_GNUC_UNUSED const FLAC__StreamDecoder *fd, void *fdata) { struct flac_data *data = (struct flac_data *) fdata; return (decoder_get_command(data->decoder) != DECODE_COMMAND_NONE && decoder_get_command(data->decoder) != DECODE_COMMAND_SEEK) || input_stream_lock_eof(data->input_stream); }
static void flac_decoder_loop(struct flac_data *data, FLAC__StreamDecoder *flac_dec, FLAC__uint64 t_start, FLAC__uint64 t_end) { struct decoder *decoder = data->decoder; enum decoder_command cmd; data->first_frame = t_start; while (true) { if (data->tag != NULL && !tag_is_empty(data->tag)) { cmd = decoder_tag(data->decoder, data->input_stream, data->tag); tag_free(data->tag); data->tag = tag_new(); } else cmd = decoder_get_command(decoder); if (cmd == DECODE_COMMAND_SEEK) { FLAC__uint64 seek_sample = t_start + decoder_seek_where(decoder) * data->audio_format.sample_rate; if (seek_sample >= t_start && (t_end == 0 || seek_sample <= t_end) && FLAC__stream_decoder_seek_absolute(flac_dec, seek_sample)) { data->next_frame = seek_sample; data->position = 0; decoder_command_finished(decoder); } else decoder_seek_error(decoder); } else if (cmd == DECODE_COMMAND_STOP || FLAC__stream_decoder_get_state(flac_dec) == FLAC__STREAM_DECODER_END_OF_STREAM) break; if (t_end != 0 && data->next_frame >= t_end) /* end of this sub track */ break; if (!FLAC__stream_decoder_process_single(flac_dec)) { cmd = decoder_get_command(decoder); if (cmd != DECODE_COMMAND_SEEK) break; } } if (cmd != DECODE_COMMAND_STOP) { flacPrintErroredState(FLAC__stream_decoder_get_state(flac_dec)); FLAC__stream_decoder_finish(flac_dec); } }
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, }; 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_eof(is)) break; 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_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", NULL }; const struct decoder_plugin pcm_decoder_plugin = { .name = "pcm", .stream_decode = pcm_stream_decode, .mime_types = pcm_mime_types, };
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; }
static void mp3_decode(struct decoder *decoder, struct input_stream *input_stream) { struct mp3_data data; struct tag *tag = NULL; struct replay_gain_info *replay_gain_info = NULL; struct audio_format audio_format; if (!mp3_open(input_stream, &data, decoder, &tag, &replay_gain_info)) { if (decoder_get_command(decoder) == DECODE_COMMAND_NONE) g_warning ("Input does not appear to be a mp3 bit stream.\n"); return; } mp3_audio_format(&data, &audio_format); decoder_initialized(decoder, &audio_format, data.input_stream->seekable, data.total_time); if (tag != NULL) { decoder_tag(decoder, input_stream, tag); tag_free(tag); } while (mp3_read(&data, &replay_gain_info)) ; if (replay_gain_info) replay_gain_info_free(replay_gain_info); if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK && data.mute_frame == MUTEFRAME_SEEK) decoder_command_finished(decoder); mp3_data_finish(&data); }
static void mp3_decode(struct decoder *decoder, struct input_stream *input_stream) { struct mp3_data data; GError *error = NULL; struct tag *tag = NULL; struct audio_format audio_format; if (!mp3_open(input_stream, &data, decoder, &tag)) { if (decoder_get_command(decoder) == DECODE_COMMAND_NONE) g_warning ("Input does not appear to be a mp3 bit stream.\n"); return; } if (!audio_format_init_checked(&audio_format, data.frame.header.samplerate, SAMPLE_FORMAT_S24_P32, MAD_NCHANNELS(&data.frame.header), &error)) { g_warning("%s", error->message); g_error_free(error); if (tag != NULL) tag_free(tag); mp3_data_finish(&data); return; } decoder_initialized(decoder, &audio_format, data.input_stream->seekable, data.total_time); if (tag != NULL) { decoder_tag(decoder, input_stream, tag); tag_free(tag); } while (mp3_read(&data)) ; mp3_data_finish(&data); }
static bool vorbis_is_open(struct vorbis_input_stream *vis, OggVorbis_File *vf, struct decoder *decoder, struct input_stream *input_stream) { vis->decoder = decoder; vis->input_stream = input_stream; vis->seekable = input_stream->seekable && (input_stream->uri == NULL || !uri_has_scheme(input_stream->uri)); int ret = ov_open_callbacks(vis, vf, NULL, 0, vorbis_is_callbacks); if (ret < 0) { if (decoder == NULL || decoder_get_command(decoder) == DECODE_COMMAND_NONE) g_warning("Failed to open Ogg Vorbis stream: %s", vorbis_strerror(ret)); return false; } return true; }
void flac_error_common_cb(const char *plugin, const FLAC__StreamDecoderErrorStatus status, struct flac_data *data) { if (decoder_get_command(data->decoder) == DECODE_COMMAND_STOP) return; switch (status) { case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC: g_warning("%s lost sync\n", plugin); break; case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER: g_warning("bad %s header\n", plugin); break; case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH: g_warning("%s crc mismatch\n", plugin); break; default: g_warning("unknown %s error\n", plugin); } }
static FLAC__StreamDecoderReadStatus flac_read_cb(G_GNUC_UNUSED const FLAC__StreamDecoder *fd, FLAC__byte buf[], flac_read_status_size_t *bytes, void *fdata) { struct flac_data *data = fdata; size_t r; r = decoder_read(data->decoder, data->input_stream, (void *)buf, *bytes); *bytes = r; if (r == 0) { if (decoder_get_command(data->decoder) != DECODE_COMMAND_NONE || input_stream_lock_eof(data->input_stream)) return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; else return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; }
/* * This does the main decoding thing. * Requires an already opened WavpackContext. */ static void wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek, struct replay_gain_info *replay_gain_info) { struct audio_format audio_format; format_samples_t format_samples; char chunk[CHUNK_SIZE]; int samples_requested, samples_got; float total_time, current_time; int bytes_per_sample, output_sample_size; int position; audio_format.sample_rate = WavpackGetSampleRate(wpc); audio_format.channels = WavpackGetReducedChannels(wpc); audio_format.bits = WavpackGetBitsPerSample(wpc); /* round bitwidth to 8-bit units */ audio_format.bits = (audio_format.bits + 7) & (~7); /* mpd handles max 24-bit samples */ if (audio_format.bits > 24) { audio_format.bits = 24; } if (!audio_format_valid(&audio_format)) { g_warning("Invalid audio format: %u:%u:%u\n", audio_format.sample_rate, audio_format.bits, audio_format.channels); return; } if ((WavpackGetMode(wpc) & MODE_FLOAT) == MODE_FLOAT) { format_samples = format_samples_float; } else { format_samples = format_samples_int; } total_time = WavpackGetNumSamples(wpc); total_time /= audio_format.sample_rate; bytes_per_sample = WavpackGetBytesPerSample(wpc); output_sample_size = audio_format_frame_size(&audio_format); /* wavpack gives us all kind of samples in a 32-bit space */ samples_requested = sizeof(chunk) / (4 * audio_format.channels); decoder_initialized(decoder, &audio_format, can_seek, total_time); position = 0; do { if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK) { if (can_seek) { int where; where = decoder_seek_where(decoder); where *= audio_format.sample_rate; if (WavpackSeekSample(wpc, where)) { position = where; decoder_command_finished(decoder); } else { decoder_seek_error(decoder); } } else { decoder_seek_error(decoder); } } if (decoder_get_command(decoder) == DECODE_COMMAND_STOP) { break; } samples_got = WavpackUnpackSamples( wpc, (int32_t *)chunk, samples_requested ); if (samples_got > 0) { int bitrate = (int)(WavpackGetInstantBitrate(wpc) / 1000 + 0.5); position += samples_got; current_time = position; current_time /= audio_format.sample_rate; format_samples( bytes_per_sample, chunk, samples_got * audio_format.channels ); decoder_data( decoder, NULL, chunk, samples_got * output_sample_size, current_time, bitrate, replay_gain_info ); } } while (samples_got > 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, ¤t_section); #else float **per_channel; long nframes = ov_read_float(&vf, &per_channel, frames_per_buffer, ¤t_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); }
/* * This does the main decoding thing. * Requires an already opened WavpackContext. */ static void wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek) { GError *error = NULL; bool is_float; enum sample_format sample_format; struct audio_format audio_format; format_samples_t format_samples; float total_time; int bytes_per_sample, output_sample_size; is_float = (WavpackGetMode(wpc) & MODE_FLOAT) != 0; sample_format = wavpack_bits_to_sample_format(is_float, WavpackGetBytesPerSample(wpc)); if (!audio_format_init_checked(&audio_format, WavpackGetSampleRate(wpc), sample_format, WavpackGetNumChannels(wpc), &error)) { g_warning("%s", error->message); g_error_free(error); return; } if (is_float) { format_samples = format_samples_float; } else { format_samples = format_samples_int; } total_time = WavpackGetNumSamples(wpc); total_time /= audio_format.sample_rate; bytes_per_sample = WavpackGetBytesPerSample(wpc); output_sample_size = audio_format_frame_size(&audio_format); /* wavpack gives us all kind of samples in a 32-bit space */ int32_t chunk[1024]; const uint32_t samples_requested = G_N_ELEMENTS(chunk) / audio_format.channels; decoder_initialized(decoder, &audio_format, can_seek, total_time); enum decoder_command cmd = decoder_get_command(decoder); while (cmd != DECODE_COMMAND_STOP) { if (cmd == DECODE_COMMAND_SEEK) { if (can_seek) { unsigned where = decoder_seek_where(decoder) * audio_format.sample_rate; if (WavpackSeekSample(wpc, where)) { decoder_command_finished(decoder); } else { decoder_seek_error(decoder); } } else { decoder_seek_error(decoder); } } uint32_t samples_got = WavpackUnpackSamples(wpc, chunk, samples_requested); if (samples_got == 0) break; int bitrate = (int)(WavpackGetInstantBitrate(wpc) / 1000 + 0.5); format_samples(bytes_per_sample, chunk, samples_got * audio_format.channels); cmd = decoder_data(decoder, NULL, chunk, samples_got * output_sample_size, bitrate); } }