Skip to content

Commit 849c401

Browse files
committed
filter/Filter: add method ReadMore()
This allows FilterPCM() to return more data, which some implementations may need to do (e.g. FFmpeg).
1 parent d8bb833 commit 849c401

File tree

8 files changed

+84
-10
lines changed

8 files changed

+84
-10
lines changed

src/filter/Filter.hxx

+19-2
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,28 @@ public:
4242
*
4343
* @param src the input buffer
4444
* @return the output buffer (will be invalidated by deleting
45-
* this object or any call to Reset(), FilterPCM() or
46-
* Flush()); may be empty if no output is currently available
45+
* this object or any call to Reset(), FilterPCM(), ReadMore()
46+
* or Flush()); may be empty if no output is currently
47+
* available
4748
*/
4849
virtual std::span<const std::byte> FilterPCM(std::span<const std::byte> src) = 0;
4950

51+
/**
52+
* Read more result data from the filter. After each
53+
* FilterPCM() call, this should be called repeatedly until it
54+
* returns an empty span.
55+
*
56+
* Throws on error.
57+
*
58+
* @return the output buffer (will be invalidated by deleting
59+
* this object or any call to Reset(), FilterPCM(), ReadMore()
60+
* or Flush()); may be empty if no output is currently
61+
* available
62+
*/
63+
virtual std::span<const std::byte> ReadMore() {
64+
return {};
65+
}
66+
5067
/**
5168
* Flush pending data and return it. This should be called
5269
* repeatedly until it returns an empty span.

src/filter/Observer.cxx

+4
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ class FilterObserver::Proxy final : public Filter {
6868
return filter->FilterPCM(src);
6969
}
7070

71+
std::span<const std::byte> ReadMore() override {
72+
return filter->ReadMore();
73+
}
74+
7175
std::span<const std::byte> Flush() override {
7276
return filter->Flush();
7377
}

src/filter/plugins/FfmpegFilter.cxx

+6
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ FfmpegFilter::FilterPCM(std::span<const std::byte> src)
8484
return ReadOutput();
8585
}
8686

87+
std::span<const std::byte>
88+
FfmpegFilter::ReadMore()
89+
{
90+
return ReadOutput();
91+
}
92+
8793
std::span<const std::byte>
8894
FfmpegFilter::Flush()
8995
{

src/filter/plugins/FfmpegFilter.hxx

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public:
5454

5555
/* virtual methods from class Filter */
5656
std::span<const std::byte> FilterPCM(std::span<const std::byte> src) override;
57+
std::span<const std::byte> ReadMore() override;
5758
std::span<const std::byte> Flush() override;
5859

5960
private:

src/filter/plugins/TwoFilters.cxx

+38-4
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,47 @@ TwoFilters::FilterPCM(std::span<const std::byte> src)
2121
}
2222

2323
std::span<const std::byte>
24-
TwoFilters::Flush()
24+
TwoFilters::ReadMore()
2525
{
26-
if (auto result = first->Flush(); !result.empty())
27-
/* Flush() output from the first Filter must be
28-
filtered by the second Filter */
26+
assert(first);
27+
assert(second);
28+
29+
/* first read all remaining data from the second filter */
30+
if (auto result = second->ReadMore(); !result.empty())
31+
return result;
32+
33+
/* now read more data from the first filter and process it
34+
with the second filter */
35+
if (auto result = first->ReadMore(); !result.empty())
36+
/* output from the first Filter must be filtered by
37+
the second Filter */
2938
return second->FilterPCM(result);
3039

40+
/* both filters have been queried and there's no more data */
41+
return {};
42+
}
43+
44+
std::span<const std::byte>
45+
TwoFilters::Flush()
46+
{
47+
assert(second);
48+
49+
/* first read all remaining data from the second filter */
50+
if (auto result = second->ReadMore(); !result.empty())
51+
return result;
52+
53+
/* now flush the first filter and process it with the second
54+
filter */
55+
if (first) {
56+
if (auto result = first->Flush(); !result.empty())
57+
/* output from the first Filter must be
58+
filtered by the second Filter */
59+
return second->FilterPCM(result);
60+
61+
first.reset();
62+
}
63+
64+
/* finally flush the second filter */
3165
return second->Flush();
3266
}
3367

src/filter/plugins/TwoFilters.hxx

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public:
2929
}
3030

3131
std::span<const std::byte> FilterPCM(std::span<const std::byte> src) override;
32+
std::span<const std::byte> ReadMore() override;
3233
std::span<const std::byte> Flush() override;
3334
};
3435

src/output/Source.cxx

+12-2
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ AudioOutputSource::GetChunkData(const MusicChunk &chunk,
138138
*replay_gain_serial_p = chunk.replay_gain_serial;
139139
}
140140

141+
/* note: the ReplayGainFilter doesn't have a
142+
ReadMore() method */
141143
data = current_replay_gain_filter->FilterPCM(data);
142144
}
143145

@@ -231,10 +233,18 @@ AudioOutputSource::Fill(Mutex &mutex)
231233
void
232234
AudioOutputSource::ConsumeData(size_t nbytes) noexcept
233235
{
236+
assert(filter);
237+
234238
pending_data = pending_data.subspan(nbytes);
235239

236-
if (pending_data.empty())
237-
DropCurrentChunk();
240+
if (pending_data.empty()) {
241+
/* give the filter a chance to return more data in
242+
another buffer */
243+
pending_data = filter->ReadMore();
244+
245+
if (pending_data.empty())
246+
DropCurrentChunk();
247+
}
238248
}
239249

240250
std::span<const std::byte>

test/run_filter.cxx

+3-2
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,9 @@ try {
122122
if (nbytes == 0)
123123
break;
124124

125-
auto dest = filter->FilterPCM(std::span{buffer}.first(nbytes));
126-
output_fd.FullWrite(dest);
125+
for (auto dest = filter->FilterPCM(std::span{buffer}.first(nbytes));
126+
!dest.empty(); dest = filter->ReadMore())
127+
output_fd.FullWrite(dest);
127128
}
128129

129130
while (true) {

0 commit comments

Comments
 (0)