Skip to content

Commit

Permalink
decoder/mpg123: implement stream_decode
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxKellermann committed Apr 3, 2024
1 parent 1745c48 commit 9c2df5c
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 4 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ ver 0.24 (not yet released)
- ffmpeg: query supported demuxers at runtime
- hybrid_dsd: remove
- mpg123: prefer over "mad"
- mpg123: support streaming

This comment has been minimized.

Copy link
@naglis

naglis Apr 19, 2024

Contributor

@MaxKellermann does this mean that the limitations documented in 8b67ae0 no longer apply?

- opus: implement bitrate calculation
- sidplay: require libsidplayfp (drop support for the original sidplay)
- wavpack: require libwavpack version 5
Expand Down
119 changes: 115 additions & 4 deletions src/decoder/plugins/Mpg123DecoderPlugin.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@

#include "Mpg123DecoderPlugin.hxx"
#include "../DecoderAPI.hxx"
#include "input/InputStream.hxx"
#include "pcm/CheckAudioFormat.hxx"
#include "tag/Handler.hxx"
#include "tag/Builder.hxx"
#include "tag/ReplayGainParser.hxx"
#include "tag/MixRampParser.hxx"
#include "fs/NarrowPath.hxx"
#include "fs/Path.hxx"
#include "lib/fmt/ExceptionFormatter.hxx"
#include "lib/fmt/RuntimeError.hxx"
#include "util/Domain.hxx"
#include "util/ScopeExit.hxx"
#include "Log.hxx"
Expand Down Expand Up @@ -56,6 +59,64 @@ mpd_mpg123_open(mpg123_handle *handle, Path path_fs)
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.
*
Expand Down Expand Up @@ -175,7 +236,7 @@ mpd_mpg123_meta(DecoderClient &client, mpg123_handle *const handle)
}

static void
Decode(DecoderClient &client, mpg123_handle &handle)
Decode(DecoderClient &client, mpg123_handle &handle, const bool seekable)
{
AudioFormat audio_format;
if (!GetAudioFormat(handle, audio_format))
Expand All @@ -189,7 +250,7 @@ Decode(DecoderClient &client, mpg123_handle &handle)
SongTime::FromScale<uint64_t>(num_samples,
audio_format.sample_rate);

client.Ready(audio_format, true, duration);
client.Ready(audio_format, seekable, duration);

struct mpg123_frameinfo info;
if (mpg123_info(&handle, &info) != MPG123_OK) {
Expand Down Expand Up @@ -254,6 +315,31 @@ Decode(DecoderClient &client, mpg123_handle &handle)
} 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
mpd_mpg123_file_decode(DecoderClient &client, Path path_fs)
{
Expand All @@ -273,7 +359,7 @@ mpd_mpg123_file_decode(DecoderClient &client, Path path_fs)
if (!mpd_mpg123_open(handle, path_fs))
return;

Decode(client, *handle);
Decode(client, *handle, true);
}

static bool
Expand Down Expand Up @@ -305,6 +391,29 @@ Scan(mpg123_handle &handle, TagHandler &handler) noexcept
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
mpd_mpg123_scan_file(Path path_fs, TagHandler &handler) noexcept
{
Expand Down Expand Up @@ -335,6 +444,8 @@ static const char *const mpg123_suffixes[] = {
};

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)
.WithSuffixes(mpg123_suffixes);

0 comments on commit 9c2df5c

Please sign in to comment.