Commit 114fcee2 authored by Max Kellermann's avatar Max Kellermann

decoder/Client: add virtual method Read()

parent b4882040
...@@ -401,6 +401,37 @@ DecoderBridge::OpenUri(const char *uri) ...@@ -401,6 +401,37 @@ DecoderBridge::OpenUri(const char *uri)
} }
} }
size_t
DecoderBridge::Read(InputStream &is, void *buffer, size_t length)
try {
assert(buffer != nullptr);
assert(dc.state == DecoderState::START ||
dc.state == DecoderState::DECODE);
if (length == 0)
return 0;
ScopeLock lock(is.mutex);
while (true) {
if (CheckCancelRead())
return 0;
if (is.IsAvailable())
break;
is.cond.wait(is.mutex);
}
size_t nbytes = is.Read(buffer, length);
assert(nbytes > 0 || is.IsEOF());
return nbytes;
} catch (const std::runtime_error &e) {
error = std::current_exception();
return 0;
}
void void
DecoderBridge::SubmitTimestamp(double t) DecoderBridge::SubmitTimestamp(double t)
{ {
......
...@@ -140,6 +140,7 @@ public: ...@@ -140,6 +140,7 @@ public:
uint64_t GetSeekFrame() override; uint64_t GetSeekFrame() override;
void SeekError() override; void SeekError() override;
InputStreamPtr OpenUri(const char *uri) override; InputStreamPtr OpenUri(const char *uri) override;
size_t Read(InputStream &is, void *buffer, size_t length) override;
void SubmitTimestamp(double t) override; void SubmitTimestamp(double t) override;
DecoderCommand SubmitData(InputStream *is, DecoderCommand SubmitData(InputStream *is,
const void *data, size_t length, const void *data, size_t length,
......
...@@ -99,6 +99,17 @@ public: ...@@ -99,6 +99,17 @@ public:
virtual InputStreamPtr OpenUri(const char *uri) = 0; virtual InputStreamPtr OpenUri(const char *uri) = 0;
/** /**
* Blocking read from the input stream.
*
* @param is the input stream to read from
* @param buffer the destination buffer
* @param length the maximum number of bytes to read
* @return the number of bytes read, or 0 if one of the following
* occurs: end of file; error; command (like SEEK or STOP).
*/
virtual size_t Read(InputStream &is, void *buffer, size_t length) = 0;
/**
* Sets the time stamp for the next data chunk [seconds]. The MPD * Sets the time stamp for the next data chunk [seconds]. The MPD
* core automatically counts it up, and a decoder plugin only needs to * core automatically counts it up, and a decoder plugin only needs to
* use this function if it thinks that adding to the time stamp based * use this function if it thinks that adding to the time stamp based
......
...@@ -19,8 +19,6 @@ ...@@ -19,8 +19,6 @@
#include "config.h" #include "config.h"
#include "DecoderAPI.hxx" #include "DecoderAPI.hxx"
#include "DecoderControl.hxx"
#include "Bridge.hxx"
#include "input/InputStream.hxx" #include "input/InputStream.hxx"
#include "Log.hxx" #include "Log.hxx"
...@@ -30,44 +28,19 @@ size_t ...@@ -30,44 +28,19 @@ size_t
decoder_read(DecoderClient *client, decoder_read(DecoderClient *client,
InputStream &is, InputStream &is,
void *buffer, size_t length) void *buffer, size_t length)
try { {
assert(buffer != nullptr); assert(buffer != nullptr);
/* XXX don't allow client==nullptr */ /* XXX don't allow client==nullptr */
if (client == nullptr) if (client != nullptr)
return is.LockRead(buffer, length); return client->Read(is, buffer, length);
auto &bridge = *(DecoderBridge *)client;
assert(bridge.dc.state == DecoderState::START ||
bridge.dc.state == DecoderState::DECODE);
if (length == 0) try {
return 0; return is.LockRead(buffer, length);
} catch (const std::runtime_error &e) {
ScopeLock lock(is.mutex);
while (true) {
if (bridge.CheckCancelRead())
return 0;
if (is.IsAvailable())
break;
is.cond.wait(is.mutex);
}
size_t nbytes = is.Read(buffer, length);
assert(nbytes > 0 || is.IsEOF());
return nbytes;
} catch (const std::runtime_error &e) {
auto *bridge = (DecoderBridge *)client;
if (bridge != nullptr)
bridge->error = std::current_exception();
else
LogError(e); LogError(e);
return 0; return 0;
}
} }
bool bool
......
...@@ -80,51 +80,15 @@ FakeDecoder::OpenUri(const char *uri) ...@@ -80,51 +80,15 @@ FakeDecoder::OpenUri(const char *uri)
} }
size_t size_t
decoder_read(gcc_unused DecoderClient *client, FakeDecoder::Read(InputStream &is, void *buffer, size_t length)
InputStream &is,
void *buffer, size_t length)
{ {
try { try {
return is.LockRead(buffer, length); return is.LockRead(buffer, length);
} catch (const std::runtime_error &) { } catch (const std::runtime_error &e) {
return 0; return 0;
} }
} }
bool
decoder_read_full(DecoderClient *client, InputStream &is,
void *_buffer, size_t size)
{
uint8_t *buffer = (uint8_t *)_buffer;
while (size > 0) {
size_t nbytes = decoder_read(client, is, buffer, size);
if (nbytes == 0)
return false;
buffer += nbytes;
size -= nbytes;
}
return true;
}
bool
decoder_skip(DecoderClient *client, InputStream &is, size_t size)
{
while (size > 0) {
char buffer[1024];
size_t nbytes = decoder_read(client, is, buffer,
std::min(sizeof(buffer), size));
if (nbytes == 0)
return false;
size -= nbytes;
}
return true;
}
void void
FakeDecoder::SubmitTimestamp(gcc_unused double t) FakeDecoder::SubmitTimestamp(gcc_unused double t)
{ {
......
...@@ -40,6 +40,7 @@ struct FakeDecoder final : DecoderClient { ...@@ -40,6 +40,7 @@ struct FakeDecoder final : DecoderClient {
uint64_t GetSeekFrame() override; uint64_t GetSeekFrame() override;
void SeekError() override; void SeekError() override;
InputStreamPtr OpenUri(const char *uri) override; InputStreamPtr OpenUri(const char *uri) override;
size_t Read(InputStream &is, void *buffer, size_t length) override;
void SubmitTimestamp(double t) override; void SubmitTimestamp(double t) override;
DecoderCommand SubmitData(InputStream *is, DecoderCommand SubmitData(InputStream *is,
const void *data, size_t length, const void *data, size_t length,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment