filter/Filter: add method ReadMore()
This allows FilterPCM() to return more data, which some implementations may need to do (e.g. FFmpeg).
This commit is contained in:
parent
d8bb833ba3
commit
849c4012c0
|
@ -42,11 +42,28 @@ public:
|
||||||
*
|
*
|
||||||
* @param src the input buffer
|
* @param src the input buffer
|
||||||
* @return the output buffer (will be invalidated by deleting
|
* @return the output buffer (will be invalidated by deleting
|
||||||
* this object or any call to Reset(), FilterPCM() or
|
* this object or any call to Reset(), FilterPCM(), ReadMore()
|
||||||
* Flush()); may be empty if no output is currently available
|
* or Flush()); may be empty if no output is currently
|
||||||
|
* available
|
||||||
*/
|
*/
|
||||||
virtual std::span<const std::byte> FilterPCM(std::span<const std::byte> src) = 0;
|
virtual std::span<const std::byte> FilterPCM(std::span<const std::byte> src) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read more result data from the filter. After each
|
||||||
|
* FilterPCM() call, this should be called repeatedly until it
|
||||||
|
* returns an empty span.
|
||||||
|
*
|
||||||
|
* Throws on error.
|
||||||
|
*
|
||||||
|
* @return the output buffer (will be invalidated by deleting
|
||||||
|
* this object or any call to Reset(), FilterPCM(), ReadMore()
|
||||||
|
* or Flush()); may be empty if no output is currently
|
||||||
|
* available
|
||||||
|
*/
|
||||||
|
virtual std::span<const std::byte> ReadMore() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush pending data and return it. This should be called
|
* Flush pending data and return it. This should be called
|
||||||
* repeatedly until it returns an empty span.
|
* repeatedly until it returns an empty span.
|
||||||
|
|
|
@ -68,6 +68,10 @@ public:
|
||||||
return filter->FilterPCM(src);
|
return filter->FilterPCM(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::span<const std::byte> ReadMore() override {
|
||||||
|
return filter->ReadMore();
|
||||||
|
}
|
||||||
|
|
||||||
std::span<const std::byte> Flush() override {
|
std::span<const std::byte> Flush() override {
|
||||||
return filter->Flush();
|
return filter->Flush();
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,12 @@ FfmpegFilter::FilterPCM(std::span<const std::byte> src)
|
||||||
return ReadOutput();
|
return ReadOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::span<const std::byte>
|
||||||
|
FfmpegFilter::ReadMore()
|
||||||
|
{
|
||||||
|
return ReadOutput();
|
||||||
|
}
|
||||||
|
|
||||||
std::span<const std::byte>
|
std::span<const std::byte>
|
||||||
FfmpegFilter::Flush()
|
FfmpegFilter::Flush()
|
||||||
{
|
{
|
||||||
|
|
|
@ -54,6 +54,7 @@ public:
|
||||||
|
|
||||||
/* virtual methods from class Filter */
|
/* virtual methods from class Filter */
|
||||||
std::span<const std::byte> FilterPCM(std::span<const std::byte> src) override;
|
std::span<const std::byte> FilterPCM(std::span<const std::byte> src) override;
|
||||||
|
std::span<const std::byte> ReadMore() override;
|
||||||
std::span<const std::byte> Flush() override;
|
std::span<const std::byte> Flush() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -20,14 +20,48 @@ TwoFilters::FilterPCM(std::span<const std::byte> src)
|
||||||
return second->FilterPCM(dest);
|
return second->FilterPCM(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::span<const std::byte>
|
||||||
|
TwoFilters::ReadMore()
|
||||||
|
{
|
||||||
|
assert(first);
|
||||||
|
assert(second);
|
||||||
|
|
||||||
|
/* first read all remaining data from the second filter */
|
||||||
|
if (auto result = second->ReadMore(); !result.empty())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* now read more data from the first filter and process it
|
||||||
|
with the second filter */
|
||||||
|
if (auto result = first->ReadMore(); !result.empty())
|
||||||
|
/* output from the first Filter must be filtered by
|
||||||
|
the second Filter */
|
||||||
|
return second->FilterPCM(result);
|
||||||
|
|
||||||
|
/* both filters have been queried and there's no more data */
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
std::span<const std::byte>
|
std::span<const std::byte>
|
||||||
TwoFilters::Flush()
|
TwoFilters::Flush()
|
||||||
{
|
{
|
||||||
|
assert(second);
|
||||||
|
|
||||||
|
/* first read all remaining data from the second filter */
|
||||||
|
if (auto result = second->ReadMore(); !result.empty())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* now flush the first filter and process it with the second
|
||||||
|
filter */
|
||||||
|
if (first) {
|
||||||
if (auto result = first->Flush(); !result.empty())
|
if (auto result = first->Flush(); !result.empty())
|
||||||
/* Flush() output from the first Filter must be
|
/* output from the first Filter must be
|
||||||
filtered by the second Filter */
|
filtered by the second Filter */
|
||||||
return second->FilterPCM(result);
|
return second->FilterPCM(result);
|
||||||
|
|
||||||
|
first.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finally flush the second filter */
|
||||||
return second->Flush();
|
return second->Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
std::span<const std::byte> FilterPCM(std::span<const std::byte> src) override;
|
std::span<const std::byte> FilterPCM(std::span<const std::byte> src) override;
|
||||||
|
std::span<const std::byte> ReadMore() override;
|
||||||
std::span<const std::byte> Flush() override;
|
std::span<const std::byte> Flush() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,8 @@ AudioOutputSource::GetChunkData(const MusicChunk &chunk,
|
||||||
*replay_gain_serial_p = chunk.replay_gain_serial;
|
*replay_gain_serial_p = chunk.replay_gain_serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* note: the ReplayGainFilter doesn't have a
|
||||||
|
ReadMore() method */
|
||||||
data = current_replay_gain_filter->FilterPCM(data);
|
data = current_replay_gain_filter->FilterPCM(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,10 +233,18 @@ AudioOutputSource::Fill(Mutex &mutex)
|
||||||
void
|
void
|
||||||
AudioOutputSource::ConsumeData(size_t nbytes) noexcept
|
AudioOutputSource::ConsumeData(size_t nbytes) noexcept
|
||||||
{
|
{
|
||||||
|
assert(filter);
|
||||||
|
|
||||||
pending_data = pending_data.subspan(nbytes);
|
pending_data = pending_data.subspan(nbytes);
|
||||||
|
|
||||||
|
if (pending_data.empty()) {
|
||||||
|
/* give the filter a chance to return more data in
|
||||||
|
another buffer */
|
||||||
|
pending_data = filter->ReadMore();
|
||||||
|
|
||||||
if (pending_data.empty())
|
if (pending_data.empty())
|
||||||
DropCurrentChunk();
|
DropCurrentChunk();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::span<const std::byte>
|
std::span<const std::byte>
|
||||||
|
|
|
@ -122,7 +122,8 @@ try {
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
auto dest = filter->FilterPCM(std::span{buffer}.first(nbytes));
|
for (auto dest = filter->FilterPCM(std::span{buffer}.first(nbytes));
|
||||||
|
!dest.empty(); dest = filter->ReadMore())
|
||||||
output_fd.FullWrite(dest);
|
output_fd.FullWrite(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue