decoder/pcm: implement RFC 2586 (audio/L16)
https://bugs.musicpd.org/view.php?id=4525
This commit is contained in:
parent
287ef181ba
commit
5a22a0c27d
1
NEWS
1
NEWS
@ -23,6 +23,7 @@ ver 0.20 (not yet released)
|
|||||||
- gme: add option "accuracy"
|
- gme: add option "accuracy"
|
||||||
- mad: reduce memory usage while scanning tags
|
- mad: reduce memory usage while scanning tags
|
||||||
- mpcdec: read the bit rate
|
- mpcdec: read the bit rate
|
||||||
|
- pcm: support audio/L16 (RFC 2586)
|
||||||
* playlist
|
* playlist
|
||||||
- cue: don't skip pregap
|
- cue: don't skip pregap
|
||||||
- embcue: fix last track
|
- embcue: fix last track
|
||||||
|
@ -1942,7 +1942,9 @@ buffer_size: 16384</programlisting>
|
|||||||
<title><varname>pcm</varname></title>
|
<title><varname>pcm</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Read raw PCM samples.
|
Read raw PCM samples. It understands the "audio/L16" MIME
|
||||||
|
type with parameters "rate" and "channels" according to RFC
|
||||||
|
2586.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -20,9 +20,12 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "PcmDecoderPlugin.hxx"
|
#include "PcmDecoderPlugin.hxx"
|
||||||
#include "../DecoderAPI.hxx"
|
#include "../DecoderAPI.hxx"
|
||||||
|
#include "CheckAudioFormat.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
#include "util/ByteReverse.hxx"
|
#include "util/ByteReverse.hxx"
|
||||||
|
#include "util/NumberParser.hxx"
|
||||||
|
#include "util/MimeType.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -30,7 +33,7 @@
|
|||||||
static void
|
static void
|
||||||
pcm_stream_decode(Decoder &decoder, InputStream &is)
|
pcm_stream_decode(Decoder &decoder, InputStream &is)
|
||||||
{
|
{
|
||||||
static constexpr AudioFormat audio_format = {
|
AudioFormat audio_format = {
|
||||||
44100,
|
44100,
|
||||||
SampleFormat::S16,
|
SampleFormat::S16,
|
||||||
2,
|
2,
|
||||||
@ -40,6 +43,66 @@ pcm_stream_decode(Decoder &decoder, InputStream &is)
|
|||||||
const bool reverse_endian = mime != nullptr &&
|
const bool reverse_endian = mime != nullptr &&
|
||||||
strcmp(mime, "audio/x-mpd-cdda-pcm-reverse") == 0;
|
strcmp(mime, "audio/x-mpd-cdda-pcm-reverse") == 0;
|
||||||
|
|
||||||
|
const bool l16 = mime != nullptr &&
|
||||||
|
GetMimeTypeBase(mime) == "audio/L16";
|
||||||
|
if (l16) {
|
||||||
|
audio_format.sample_rate = 0;
|
||||||
|
audio_format.channels = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto mime_parameters = ParseMimeTypeParameters(mime);
|
||||||
|
Error error;
|
||||||
|
|
||||||
|
/* MIME type parameters according to RFC 2586 */
|
||||||
|
auto i = mime_parameters.find("rate");
|
||||||
|
if (i != mime_parameters.end()) {
|
||||||
|
const char *s = i->second.c_str();
|
||||||
|
char *endptr;
|
||||||
|
unsigned value = ParseUnsigned(s, &endptr);
|
||||||
|
if (endptr == s || *endptr != 0) {
|
||||||
|
FormatWarning(audio_format_domain,
|
||||||
|
"Failed to parse sample rate: %s",
|
||||||
|
s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!audio_check_sample_rate(value, error)) {
|
||||||
|
LogError(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
audio_format.sample_rate = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = mime_parameters.find("channels");
|
||||||
|
if (i != mime_parameters.end()) {
|
||||||
|
const char *s = i->second.c_str();
|
||||||
|
char *endptr;
|
||||||
|
unsigned value = ParseUnsigned(s, &endptr);
|
||||||
|
if (endptr == s || *endptr != 0) {
|
||||||
|
FormatWarning(audio_format_domain,
|
||||||
|
"Failed to parse sample rate: %s",
|
||||||
|
s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!audio_check_channel_count(value, error)) {
|
||||||
|
LogError(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
audio_format.channels = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio_format.sample_rate == 0) {
|
||||||
|
FormatWarning(audio_format_domain,
|
||||||
|
"Missing 'rate' parameter: %s",
|
||||||
|
mime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto frame_size = audio_format.GetFrameSize();
|
const auto frame_size = audio_format.GetFrameSize();
|
||||||
|
|
||||||
const auto total_time = is.KnownSize()
|
const auto total_time = is.KnownSize()
|
||||||
@ -88,6 +151,9 @@ pcm_stream_decode(Decoder &decoder, InputStream &is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *const pcm_mime_types[] = {
|
static const char *const pcm_mime_types[] = {
|
||||||
|
/* RFC 2586 */
|
||||||
|
"audio/L16",
|
||||||
|
|
||||||
/* for streams obtained by the cdio_paranoia input plugin */
|
/* for streams obtained by the cdio_paranoia input plugin */
|
||||||
"audio/x-mpd-cdda-pcm",
|
"audio/x-mpd-cdda-pcm",
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user