static void sndfile_stream_decode(struct decoder *decoder, struct input_stream *is) { GError *error = NULL; SNDFILE *sf; SF_INFO info; struct audio_format audio_format; size_t frame_size; sf_count_t read_frames, num_frames; int buffer[4096]; enum decoder_command cmd; info.format = 0; sf = sf_open_virtual(&vio, SFM_READ, &info, is); if (sf == NULL) { g_warning("sf_open_virtual() failed"); return; } /* for now, always read 32 bit samples. Later, we could lower MPD's CPU usage by reading 16 bit samples with sf_readf_short() on low-quality source files. */ if (!audio_format_init_checked(&audio_format, info.samplerate, SAMPLE_FORMAT_S32, info.channels, &error)) { g_warning("%s", error->message); g_error_free(error); return; } decoder_initialized(decoder, &audio_format, info.seekable, frame_to_time(info.frames, &audio_format)); frame_size = audio_format_frame_size(&audio_format); read_frames = sizeof(buffer) / frame_size; do { num_frames = sf_readf_int(sf, buffer, read_frames); if (num_frames <= 0) break; cmd = decoder_data(decoder, is, buffer, num_frames * frame_size, 0); if (cmd == DECODE_COMMAND_SEEK) { sf_count_t c = time_to_frame(decoder_seek_where(decoder), &audio_format); c = sf_seek(sf, c, SEEK_SET); if (c < 0) decoder_seek_error(decoder); else decoder_command_finished(decoder); cmd = DECODE_COMMAND_NONE; } } while (cmd == DECODE_COMMAND_NONE); sf_close(sf); }
static void flac_got_stream_info(struct flac_data *data, const FLAC__StreamMetadata_StreamInfo *stream_info) { if (data->initialized || data->unsupported) return; GError *error = NULL; if (!audio_format_init_checked(&data->audio_format, stream_info->sample_rate, flac_sample_format(stream_info->bits_per_sample), stream_info->channels, &error)) { g_warning("%s", error->message); g_error_free(error); data->unsupported = true; return; } data->frame_size = audio_format_frame_size(&data->audio_format); if (data->total_frames == 0) data->total_frames = stream_info->total_samples; data->initialized = true; }
/** * This function attempts to call decoder_initialized() in case there * was no STREAMINFO block. This is allowed for nonseekable streams, * where the server sends us only a part of the file, without * providing the STREAMINFO block from the beginning of the file * (e.g. when seeking with SqueezeBox Server). */ static bool flac_got_first_frame(struct flac_data *data, const FLAC__FrameHeader *header) { if (data->unsupported) return false; GError *error = NULL; if (!audio_format_init_checked(&data->audio_format, header->sample_rate, flac_sample_format(header->bits_per_sample), header->channels, &error)) { g_warning("%s", error->message); g_error_free(error); data->unsupported = true; return false; } data->frame_size = audio_format_frame_size(&data->audio_format); decoder_initialized(data->decoder, &data->audio_format, data->input_stream->seekable, (float)data->total_frames / (float)data->audio_format.sample_rate); data->initialized = true; return true; }
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 void dsf_stream_decode(struct decoder *decoder, struct input_stream *is) { struct dsf_metadata metadata = { .sample_rate = 0, .channels = 0, }; /* check if it is a proper DSF file */ if (!dsf_read_metadata(decoder, is, &metadata)) return; GError *error = NULL; struct audio_format audio_format; if (!audio_format_init_checked(&audio_format, metadata.sample_rate / 8, SAMPLE_FORMAT_DSD, metadata.channels, &error)) { g_warning("%s", error->message); g_error_free(error); return; } /* success: file was recognized */ decoder_initialized(decoder, &audio_format, false, -1); if (!dsf_decode_chunk(decoder, is, metadata.channels, metadata.chunk_size, metadata.bitreverse)) return; } static bool dsf_scan_stream(struct input_stream *is, G_GNUC_UNUSED const struct tag_handler *handler, G_GNUC_UNUSED void *handler_ctx) { struct dsf_metadata metadata = { .sample_rate = 0, .channels = 0, }; /* check DSF metadata */ if (!dsf_read_metadata(NULL, is, &metadata)) return false; struct audio_format audio_format; if (!audio_format_init_checked(&audio_format, metadata.sample_rate / 8, SAMPLE_FORMAT_DSD, metadata.channels, NULL)) /* refuse to parse files which we cannot play anyway */ return false; return true; } static const char *const dsf_suffixes[] = { "dsf", NULL }; static const char *const dsf_mime_types[] = { "application/x-dsf", NULL }; const struct decoder_plugin dsf_decoder_plugin = { .name = "dsf", .stream_decode = dsf_stream_decode, .scan_stream = dsf_scan_stream, .suffixes = dsf_suffixes, .mime_types = dsf_mime_types, };
/* 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, ¤t_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); }
static void dsdiff_stream_decode(struct decoder *decoder, struct input_stream *is) { struct dsdiff_metadata metadata = { .sample_rate = 0, .channels = 0, }; struct dsdiff_chunk_header chunk_header; /* First see if it is is a DFF file */ if (!dsdiff_read_metadata(decoder, is, &metadata, &chunk_header)) { /* It was not a DFF file, now check if it is a DSF file */ if (!dsf_read_metadata(decoder, is, &metadata)) return; } GError *error = NULL; struct audio_format audio_format; if (!audio_format_init_checked(&audio_format, metadata.sample_rate / 8, SAMPLE_FORMAT_DSD, metadata.channels, &error)) { g_warning("%s", error->message); g_error_free(error); return; } /* success: file was recognized */ decoder_initialized(decoder, &audio_format, false, -1); if (!metadata.fileisdff) { uint64_t chunk_size = metadata.chunk_size; if (!dsdiff_decode_chunk(decoder, is, metadata.channels, chunk_size, metadata.fileisdff, metadata.bitreverse)) return; } else { /* every iteration of the following loop decodes one "DSD" chunk from a DFF file */ while (true) { uint64_t chunk_size = dsdiff_chunk_size(&chunk_header); if (dsdiff_id_equals(&chunk_header.id, "DSD ")) { if (!dsdiff_decode_chunk(decoder, is, metadata.channels, chunk_size, metadata.fileisdff, /* Set bitreverse to false for DFF files */ false)) break; } else { /* ignore other chunks */ if (!dsdiff_skip(decoder, is, chunk_size)) break; } /* read next chunk header; the first one was read by dsdiff_read_metadata() */ if (!dsdiff_read_chunk_header(decoder, is, &chunk_header)) break; } } } static bool dsdiff_scan_stream(struct input_stream *is, G_GNUC_UNUSED const struct tag_handler *handler, G_GNUC_UNUSED void *handler_ctx) { struct dsdiff_metadata metadata = { .sample_rate = 0, .channels = 0, }; struct dsdiff_chunk_header chunk_header; /* First check for DFF metadata */ if (!dsdiff_read_metadata(NULL, is, &metadata, &chunk_header)) { /* It was not an DFF file, now check for DSF metadata */ if (!dsf_read_metadata(NULL, is, &metadata)) return false; } struct audio_format audio_format; if (!audio_format_init_checked(&audio_format, metadata.sample_rate / 8, SAMPLE_FORMAT_DSD, metadata.channels, NULL)) /* refuse to parse files which we cannot play anyway */ return false; /* no total time estimate, no tags implemented yet */ return true; } static const char *const dsdiff_suffixes[] = { "dff", "dsf", NULL }; static const char *const dsdiff_mime_types[] = { "application/x-dff", "application/x-dsf", NULL }; const struct decoder_plugin dsdiff_decoder_plugin = { .name = "dsdiff", .init = dsdiff_init, .stream_decode = dsdiff_stream_decode, .scan_stream = dsdiff_scan_stream, .suffixes = dsdiff_suffixes, .mime_types = dsdiff_mime_types, };
static void audiofile_stream_decode(struct decoder *decoder, struct input_stream *is) { GError *error = NULL; AFvirtualfile *vf; int fs, frame_count; AFfilehandle af_fp; struct audio_format audio_format; float total_time; uint16_t bit_rate; int ret; char chunk[CHUNK_SIZE]; enum decoder_command cmd; if (!is->seekable) { g_warning("not seekable"); return; } vf = setup_virtual_fops(is); af_fp = afOpenVirtualFile(vf, "r", NULL); if (af_fp == AF_NULL_FILEHANDLE) { g_warning("failed to input stream\n"); return; } if (!audio_format_init_checked(&audio_format, afGetRate(af_fp, AF_DEFAULT_TRACK), audiofile_setup_sample_format(af_fp), afGetVirtualChannels(af_fp, AF_DEFAULT_TRACK), &error)) { g_warning("%s", error->message); g_error_free(error); afCloseFile(af_fp); return; } frame_count = afGetFrameCount(af_fp, AF_DEFAULT_TRACK); total_time = ((float)frame_count / (float)audio_format.sample_rate); bit_rate = (uint16_t)(is->size * 8.0 / total_time / 1000.0 + 0.5); fs = (int)afGetVirtualFrameSize(af_fp, AF_DEFAULT_TRACK, 1); decoder_initialized(decoder, &audio_format, true, total_time); do { ret = afReadFrames(af_fp, AF_DEFAULT_TRACK, chunk, CHUNK_SIZE / fs); if (ret <= 0) break; cmd = decoder_data(decoder, NULL, chunk, ret * fs, bit_rate); if (cmd == DECODE_COMMAND_SEEK) { AFframecount frame = decoder_seek_where(decoder) * audio_format.sample_rate; afSeekFrame(af_fp, AF_DEFAULT_TRACK, frame); decoder_command_finished(decoder); cmd = DECODE_COMMAND_NONE; } } while (cmd == DECODE_COMMAND_NONE); afCloseFile(af_fp); }
/* 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); } }