Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/decoder/Bridge.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,19 @@ DecoderBridge::OpenUri(std::string_view uri)
}
}

bool
DecoderBridge::Seek(InputStream &is, offset_type new_offset) noexcept
try {
assert(dc.state == DecoderState::START ||
dc.state == DecoderState::DECODE);

is.LockSeek(new_offset);
return true;
} catch (...) {
error = std::current_exception();
return false;
}

size_t
DecoderBridge::Read(InputStream &is, std::span<std::byte> dest) noexcept
try {
Expand Down
1 change: 1 addition & 0 deletions src/decoder/Bridge.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ public:
uint64_t GetSeekFrame() noexcept override;
void SeekError(std::exception_ptr &&_error) noexcept override;
InputStreamPtr OpenUri(std::string_view uri) override;
bool Seek(InputStream &is, offset_type new_offset) noexcept override;
size_t Read(InputStream &is,
std::span<std::byte> dest) noexcept override;
void SubmitTimestamp(FloatDuration t) noexcept override;
Expand Down
8 changes: 8 additions & 0 deletions src/decoder/Client.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "Command.hxx"
#include "Chrono.hxx"
#include "input/Offset.hxx"
#include "input/Ptr.hxx"

#include <cstddef>
Expand Down Expand Up @@ -86,6 +87,13 @@ public:
*/
virtual InputStreamPtr OpenUri(std::string_view uri) = 0;

/**
* Wrapper for InputStream::LockSeek().
*
* @return true on success, false on error
*/
virtual bool Seek(InputStream &is, offset_type new_offset) noexcept = 0;

/**
* Blocking read from the input stream.
*
Expand Down
49 changes: 44 additions & 5 deletions src/decoder/DecoderAPI.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "DecoderAPI.hxx"
#include "input/InputStream.hxx"
#include "util/IntOverflow.hxx"
#include "Log.hxx"

#include <cassert>
Expand Down Expand Up @@ -58,18 +59,56 @@ decoder_read_full(DecoderClient *client, InputStream &is,
}

bool
decoder_skip(DecoderClient *client, InputStream &is, size_t size) noexcept
decoder_skip(DecoderClient *client, InputStream &is, offset_type delta) noexcept
{
while (size > 0) {
if (delta > 1024 && is.IsSeekable() &&
(delta > 1024 * 1024 || is.CheapSeeking())) {
offset_type new_offset;
if (AddOverflow(is.GetOffset(), delta, new_offset))
return false;

return decoder_seek(client, is, new_offset);
}

if (delta > 4 * 1024 * 1024)
/* skipping that much would be too expensive */
return false;

while (delta > 0) {
std::byte buffer[1024];

size_t nbytes = decoder_read(client, is,
std::span{buffer, std::min(sizeof(buffer), size)});
std::span<std::byte> dest{buffer};
if (delta < dest.size())
dest = dest.first(delta);

size_t nbytes = decoder_read(client, is, dest);
if (nbytes == 0)
return false;

size -= nbytes;
delta -= nbytes;
}

return true;
}

bool
decoder_seek(DecoderClient *client, InputStream &is, offset_type new_offset) noexcept
{
if (is.IsSeekable()) {
if (client != nullptr)
return client->Seek(is, new_offset);

try {
is.LockSeek(new_offset);
return true;
} catch (...) {
LogError(std::current_exception());
return false;
}
}

if (is.GetOffset() > new_offset)
return false;

return decoder_skip(client, is, new_offset - is.GetOffset());
}
17 changes: 16 additions & 1 deletion src/decoder/DecoderAPI.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// IWYU pragma: begin_exports

#include "Client.hxx"
#include "input/Offset.hxx"
#include "input/Ptr.hxx"
#include "Command.hxx"
#include "DecoderPlugin.hxx"
Expand Down Expand Up @@ -46,10 +47,12 @@ class StopDecoder {};
* @return the number of bytes read, or 0 if one of the following
* occurs: end of file; error; command (like SEEK or STOP).
*/
[[nodiscard]]
size_t
decoder_read(DecoderClient *decoder, InputStream &is,
std::span<std::byte> dest) noexcept;

[[nodiscard]]
static inline size_t
decoder_read(DecoderClient &decoder, InputStream &is,
std::span<std::byte> dest) noexcept
Expand All @@ -65,6 +68,7 @@ decoder_read(DecoderClient &decoder, InputStream &is,
* @return the number of bytes read, or 0 if one of the following
* occurs: end of file; error; command (like SEEK or STOP).
*/
[[nodiscard]]
size_t
decoder_read_much(DecoderClient *decoder, InputStream &is,
std::span<std::byte> dest) noexcept;
Expand All @@ -76,6 +80,7 @@ decoder_read_much(DecoderClient *decoder, InputStream &is,
* @return true on success, false on error or command or not enough
* data
*/
[[nodiscard]]
bool
decoder_read_full(DecoderClient *decoder, InputStream &is,
std::span<std::byte> dest) noexcept;
Expand All @@ -85,5 +90,15 @@ decoder_read_full(DecoderClient *decoder, InputStream &is,
*
* @return true on success, false on error or command
*/
[[nodiscard]]
bool
decoder_skip(DecoderClient *decoder, InputStream &is, size_t size) noexcept;
decoder_skip(DecoderClient *decoder, InputStream &is, offset_type delta) noexcept;

/**
* Wrapper for InputStream::LockSeek().
*
* @return true on success, false on error or command
*/
[[nodiscard]]
bool
decoder_seek(DecoderClient *decoder, InputStream &is, offset_type new_offset) noexcept;
46 changes: 3 additions & 43 deletions src/decoder/plugins/DsdLib.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -9,58 +9,18 @@

#include "config.h"
#include "DsdLib.hxx"
#include "../DecoderAPI.hxx"
#include "input/InputStream.hxx"
#include "util/IntOverflow.hxx"

#ifdef ENABLE_ID3TAG
#include "../DecoderAPI.hxx"
#include "tag/Id3Limits.hxx"
#include "tag/Id3Parse.hxx"
#include "tag/Id3Scan.hxx"
#include "input/InputStream.hxx"
#include "util/AllocatedArray.hxx"
#endif

#include <stdlib.h>

bool
dsdlib_skip_to(DecoderClient *client, InputStream &is,
offset_type offset)
{
if (is.IsSeekable()) {
is.LockSeek(offset);
return true;
}

if (is.GetOffset() > offset)
return false;

return dsdlib_skip(client, is, offset - is.GetOffset());
}

bool
dsdlib_skip(DecoderClient *client, InputStream &is,
offset_type delta)
{
if (delta == 0)
return true;

if (is.IsSeekable()) {
offset_type new_offset;
if (AddOverflow(is.GetOffset(), delta, new_offset))
return false;

is.LockSeek(is.GetOffset() + delta);
return true;
}

if (delta > 1024 * 1024)
/* don't skip more than one megabyte; it would be too
expensive */
return false;

return decoder_skip(client, is, delta);
}

bool
dsdlib_valid_freq(uint32_t samplefreq) noexcept
{
Expand Down Expand Up @@ -97,7 +57,7 @@ dsdlib_tag_id3(DecoderClient *client, InputStream &is,
if (count64 < 10 || count64 > MAX_ID3_TAG_SIZE)
return false;

if (!dsdlib_skip_to(client, is, tagoffset))
if (!decoder_seek(client, is, tagoffset))
return false;

const id3_length_t count = count64;
Expand Down
20 changes: 0 additions & 20 deletions src/decoder/plugins/DsdLib.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,6 @@ struct DsdId {
}
};

/**
* Skip the #InputStream to the specified offset.
*
* On error, either throws exception or returns false.
*/
[[nodiscard]]
bool
dsdlib_skip_to(DecoderClient *client, InputStream &is,
offset_type offset);

/**
* Skip some bytes from the #InputStream.
*
* On error, either throws exception or returns false.
*/
[[nodiscard]]
bool
dsdlib_skip(DecoderClient *client, InputStream &is,
offset_type delta);

/**
* Check if the sample frequency is a valid DSD frequency.
**/
Expand Down
20 changes: 10 additions & 10 deletions src/decoder/plugins/DsdiffDecoderPlugin.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,11 @@ dsdiff_read_payload(DecoderClient *client, InputStream &is,
static bool
dsdiff_read_partial_payload(DecoderClient *client, InputStream &is,
const DsdiffChunkHeader &header,
std::span<std::byte> dest)
std::span<std::byte> dest) noexcept
{
return header.GetSize() >= dest.size() &&
decoder_read_full(client, is, dest) &&
dsdlib_skip(client, is, header.GetPaddedSize() - dest.size());
decoder_skip(client, is, header.GetPaddedSize() - dest.size());
}

/**
Expand Down Expand Up @@ -175,7 +175,7 @@ dsdiff_read_prop_snd(DecoderClient *client, InputStream &is,
} else {
/* ignore unknown chunk */

if (!dsdlib_skip_to(client, is, chunk_end_offset))
if (!decoder_seek(client, is, chunk_end_offset))
return false;
}
}
Expand All @@ -201,7 +201,7 @@ dsdiff_read_prop(DecoderClient *client, InputStream &is,
return dsdiff_read_prop_snd(client, is, metadata, prop_size, end_offset);
else
/* ignore unknown PROP chunk */
return dsdlib_skip_to(client, is, end_offset);
return decoder_seek(client, is, end_offset);
}

static void
Expand All @@ -210,7 +210,7 @@ dsdiff_handle_native_tag(DecoderClient *client, InputStream &is,
offset_type tagoffset,
TagType type)
{
if (!dsdlib_skip_to(client, is, tagoffset))
if (!decoder_seek(client, is, tagoffset))
return;

struct dsdiff_native_tag metatag;
Expand Down Expand Up @@ -252,7 +252,7 @@ dsdiff_read_metadata_extra(DecoderClient *client, InputStream &is,
{

/* skip from DSD data to next chunk header */
if (!dsdlib_skip(client, is, metadata.chunk_size))
if (!decoder_skip(client, is, metadata.chunk_size))
return false;
if (!dsdiff_read_chunk_header(client, is, chunk_header))
return false;
Expand Down Expand Up @@ -295,7 +295,7 @@ dsdiff_read_metadata_extra(DecoderClient *client, InputStream &is,
}
#endif

if (!dsdlib_skip(client, is, chunk_size))
if (!decoder_skip(client, is, chunk_size))
break;
} while (dsdiff_read_chunk_header(client, is, chunk_header));

Expand Down Expand Up @@ -355,7 +355,7 @@ dsdiff_read_metadata(DecoderClient *client, InputStream &is,
return true;
} else {
/* ignore unknown chunk */
if (!dsdlib_skip_to(client, is, chunk_end_offset))
if (!decoder_seek(client, is, chunk_end_offset))
return false;
}
}
Expand Down Expand Up @@ -404,8 +404,8 @@ dsdiff_decode_chunk(DecoderClient &client, InputStream &is,
}

try {
if (dsdlib_skip_to(&client, is,
start_offset + offset)) {
if (decoder_seek(&client, is,
start_offset + offset)) {
client.CommandFinished();
remaining_bytes = total_bytes - offset;
} else
Expand Down
2 changes: 1 addition & 1 deletion src/decoder/plugins/DsfDecoderPlugin.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ dsf_decode_chunk(DecoderClient &client, InputStream &is,
start_offset + block * block_size;

try {
if (dsdlib_skip_to(&client, is, offset)) {
if (decoder_seek(&client, is, offset)) {
client.CommandFinished();
i = block;
} else
Expand Down
8 changes: 4 additions & 4 deletions src/decoder/plugins/MadDecoderPlugin.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,8 @@ MadDecoder::ParseId3(size_t tagsize, Tag *mpd_tag) noexcept
"ID3 tag is too large: {}",
tagsize);

mad_stream_skip(&stream, this_frame.size());
decoder_skip(client, input_stream, tagsize - this_frame.size());
if (decoder_skip(client, input_stream, tagsize - this_frame.size()))
mad_stream_skip(&stream, this_frame.size());
return;
}

Expand Down Expand Up @@ -327,8 +327,8 @@ MadDecoder::ParseId3(size_t tagsize, Tag *mpd_tag) noexcept
if (tagsize <= this_frame.size()) {
mad_stream_skip(&stream, tagsize);
} else {
mad_stream_skip(&stream, this_frame.size());
decoder_skip(client, input_stream, tagsize - this_frame.size());
if (decoder_skip(client, input_stream, tagsize - this_frame.size()))
mad_stream_skip(&stream, this_frame.size());
}
#endif
}
Expand Down
10 changes: 10 additions & 0 deletions src/lib/chromaprint/DecoderClient.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ ChromaprintDecoderClient::SubmitAudio(InputStream *,
return GetCommand();
}

bool
ChromaprintDecoderClient::Seek(InputStream &is, offset_type new_offset) noexcept
try {
is.LockSeek(new_offset);
return true;
} catch (...) {
error = std::current_exception();
return false;
}

size_t
ChromaprintDecoderClient::Read(InputStream &is,
std::span<std::byte> dest) noexcept
Expand Down
Loading
Loading