decoder/mpg123: implement stream_decode
This commit is contained in:
parent
1745c485f3
commit
9c2df5ce19
1
NEWS
1
NEWS
|
@ -32,6 +32,7 @@ ver 0.24 (not yet released)
|
||||||
- ffmpeg: query supported demuxers at runtime
|
- ffmpeg: query supported demuxers at runtime
|
||||||
- hybrid_dsd: remove
|
- hybrid_dsd: remove
|
||||||
- mpg123: prefer over "mad"
|
- mpg123: prefer over "mad"
|
||||||
|
- mpg123: support streaming
|
||||||
- opus: implement bitrate calculation
|
- opus: implement bitrate calculation
|
||||||
- sidplay: require libsidplayfp (drop support for the original sidplay)
|
- sidplay: require libsidplayfp (drop support for the original sidplay)
|
||||||
- wavpack: require libwavpack version 5
|
- wavpack: require libwavpack version 5
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "Mpg123DecoderPlugin.hxx"
|
#include "Mpg123DecoderPlugin.hxx"
|
||||||
#include "../DecoderAPI.hxx"
|
#include "../DecoderAPI.hxx"
|
||||||
|
#include "input/InputStream.hxx"
|
||||||
#include "pcm/CheckAudioFormat.hxx"
|
#include "pcm/CheckAudioFormat.hxx"
|
||||||
#include "tag/Handler.hxx"
|
#include "tag/Handler.hxx"
|
||||||
#include "tag/Builder.hxx"
|
#include "tag/Builder.hxx"
|
||||||
|
@ -10,6 +11,8 @@
|
||||||
#include "tag/MixRampParser.hxx"
|
#include "tag/MixRampParser.hxx"
|
||||||
#include "fs/NarrowPath.hxx"
|
#include "fs/NarrowPath.hxx"
|
||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
|
#include "lib/fmt/ExceptionFormatter.hxx"
|
||||||
|
#include "lib/fmt/RuntimeError.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
@ -56,6 +59,64 @@ mpd_mpg123_open(mpg123_handle *handle, Path path_fs)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct mpd_mpg123_iohandle {
|
||||||
|
DecoderClient *client;
|
||||||
|
InputStream &is;
|
||||||
|
};
|
||||||
|
|
||||||
|
static mpg123_ssize_t
|
||||||
|
mpd_mpg123_read(void *_iohandle, void *data, size_t size) noexcept
|
||||||
|
{
|
||||||
|
auto &iohandle = *reinterpret_cast<mpd_mpg123_iohandle *>(_iohandle);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return decoder_read_much(iohandle.client, iohandle.is, data, size);
|
||||||
|
} catch (...) {
|
||||||
|
LogError(std::current_exception(), "Read failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static off_t
|
||||||
|
mpd_mpg123_lseek(void *_iohandle, off_t offset, int whence) noexcept
|
||||||
|
{
|
||||||
|
auto &iohandle = *reinterpret_cast<mpd_mpg123_iohandle *>(_iohandle);
|
||||||
|
|
||||||
|
if (whence != SEEK_SET)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
iohandle.is.LockSeek(offset);
|
||||||
|
return offset;
|
||||||
|
} catch (...) {
|
||||||
|
LogError(std::current_exception(), "Seek failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens an #InputStream with an existing #mpg123_handle.
|
||||||
|
*
|
||||||
|
* Throws on error.
|
||||||
|
*
|
||||||
|
* @param handle a handle which was created before; on error, this
|
||||||
|
* function will not free it
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
mpd_mpg123_open_stream(mpg123_handle &handle, mpd_mpg123_iohandle &iohandle)
|
||||||
|
{
|
||||||
|
if (int error = mpg123_replace_reader_handle(&handle, mpd_mpg123_read, mpd_mpg123_lseek,
|
||||||
|
nullptr);
|
||||||
|
error != MPG123_OK)
|
||||||
|
throw FmtRuntimeError("mpg123_replace_reader() failed: %s",
|
||||||
|
mpg123_plain_strerror(error));
|
||||||
|
|
||||||
|
if (int error = mpg123_open_handle(&handle, &iohandle);
|
||||||
|
error != MPG123_OK)
|
||||||
|
throw FmtRuntimeError("mpg123_open_handle() failed: %s",
|
||||||
|
mpg123_plain_strerror(error));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert libmpg123's format to an #AudioFormat instance.
|
* Convert libmpg123's format to an #AudioFormat instance.
|
||||||
*
|
*
|
||||||
|
@ -175,7 +236,7 @@ mpd_mpg123_meta(DecoderClient &client, mpg123_handle *const handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Decode(DecoderClient &client, mpg123_handle &handle)
|
Decode(DecoderClient &client, mpg123_handle &handle, const bool seekable)
|
||||||
{
|
{
|
||||||
AudioFormat audio_format;
|
AudioFormat audio_format;
|
||||||
if (!GetAudioFormat(handle, audio_format))
|
if (!GetAudioFormat(handle, audio_format))
|
||||||
|
@ -189,7 +250,7 @@ Decode(DecoderClient &client, mpg123_handle &handle)
|
||||||
SongTime::FromScale<uint64_t>(num_samples,
|
SongTime::FromScale<uint64_t>(num_samples,
|
||||||
audio_format.sample_rate);
|
audio_format.sample_rate);
|
||||||
|
|
||||||
client.Ready(audio_format, true, duration);
|
client.Ready(audio_format, seekable, duration);
|
||||||
|
|
||||||
struct mpg123_frameinfo info;
|
struct mpg123_frameinfo info;
|
||||||
if (mpg123_info(&handle, &info) != MPG123_OK) {
|
if (mpg123_info(&handle, &info) != MPG123_OK) {
|
||||||
|
@ -254,6 +315,31 @@ Decode(DecoderClient &client, mpg123_handle &handle)
|
||||||
} while (cmd == DecoderCommand::NONE);
|
} while (cmd == DecoderCommand::NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mpd_mpg123_stream_decode(DecoderClient &client, InputStream &is)
|
||||||
|
{
|
||||||
|
/* open the file */
|
||||||
|
|
||||||
|
int error;
|
||||||
|
mpg123_handle *const handle = mpg123_new(nullptr, &error);
|
||||||
|
if (handle == nullptr) {
|
||||||
|
FmtError(mpg123_domain,
|
||||||
|
"mpg123_new() failed: {}",
|
||||||
|
mpg123_plain_strerror(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AtScopeExit(handle) { mpg123_delete(handle); };
|
||||||
|
|
||||||
|
struct mpd_mpg123_iohandle iohandle{
|
||||||
|
.client = &client,
|
||||||
|
.is = is,
|
||||||
|
};
|
||||||
|
|
||||||
|
mpd_mpg123_open_stream(*handle, iohandle);
|
||||||
|
Decode(client, *handle, is.IsSeekable());
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mpd_mpg123_file_decode(DecoderClient &client, Path path_fs)
|
mpd_mpg123_file_decode(DecoderClient &client, Path path_fs)
|
||||||
{
|
{
|
||||||
|
@ -273,7 +359,7 @@ mpd_mpg123_file_decode(DecoderClient &client, Path path_fs)
|
||||||
if (!mpd_mpg123_open(handle, path_fs))
|
if (!mpd_mpg123_open(handle, path_fs))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Decode(client, *handle);
|
Decode(client, *handle, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -305,6 +391,29 @@ Scan(mpg123_handle &handle, TagHandler &handler) noexcept
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
mpd_mpg123_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
mpg123_handle *const handle = mpg123_new(nullptr, &error);
|
||||||
|
if (handle == nullptr) {
|
||||||
|
FmtError(mpg123_domain,
|
||||||
|
"mpg123_new() failed: {}",
|
||||||
|
mpg123_plain_strerror(error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AtScopeExit(handle) { mpg123_delete(handle); };
|
||||||
|
|
||||||
|
struct mpd_mpg123_iohandle iohandle{
|
||||||
|
.client = nullptr,
|
||||||
|
.is = is,
|
||||||
|
};
|
||||||
|
|
||||||
|
mpd_mpg123_open_stream(*handle, iohandle);
|
||||||
|
return Scan(*handle, handler);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
mpd_mpg123_scan_file(Path path_fs, TagHandler &handler) noexcept
|
mpd_mpg123_scan_file(Path path_fs, TagHandler &handler) noexcept
|
||||||
{
|
{
|
||||||
|
@ -335,6 +444,8 @@ static const char *const mpg123_suffixes[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr DecoderPlugin mpg123_decoder_plugin =
|
constexpr DecoderPlugin mpg123_decoder_plugin =
|
||||||
DecoderPlugin("mpg123", mpd_mpg123_file_decode, mpd_mpg123_scan_file)
|
DecoderPlugin("mpg123",
|
||||||
|
mpd_mpg123_stream_decode, mpd_mpg123_scan_stream,
|
||||||
|
mpd_mpg123_file_decode, mpd_mpg123_scan_file)
|
||||||
.WithInit(mpd_mpg123_init, mpd_mpg123_finish)
|
.WithInit(mpd_mpg123_init, mpd_mpg123_finish)
|
||||||
.WithSuffixes(mpg123_suffixes);
|
.WithSuffixes(mpg123_suffixes);
|
||||||
|
|
Loading…
Reference in New Issue