input/ffmpeg: offload FFmpeg calls to thread

Prepare for interruptible I/O.
This commit is contained in:
Max Kellermann 2024-07-30 12:27:51 +02:00
parent ec30716e01
commit 959826d1d1
1 changed files with 33 additions and 41 deletions

View File

@ -7,36 +7,35 @@
#include "FfmpegInputPlugin.hxx" #include "FfmpegInputPlugin.hxx"
#include "lib/ffmpeg/IOContext.hxx" #include "lib/ffmpeg/IOContext.hxx"
#include "lib/ffmpeg/Init.hxx" #include "lib/ffmpeg/Init.hxx"
#include "../InputStream.hxx" #include "../ThreadInputStream.hxx"
#include "PluginUnavailable.hxx" #include "PluginUnavailable.hxx"
#include "../InputPlugin.hxx" #include "../InputPlugin.hxx"
#include "util/StringAPI.hxx" #include "util/StringAPI.hxx"
class FfmpegInputStream final : public InputStream { class FfmpegInputStream final : public ThreadInputStream {
static constexpr std::size_t BUFFER_SIZE = 256 * 1024;
Ffmpeg::IOContext io; Ffmpeg::IOContext io;
public: public:
FfmpegInputStream(const char *_uri, Mutex &_mutex) FfmpegInputStream(const char *_uri, Mutex &_mutex)
:InputStream(_uri, _mutex), :ThreadInputStream("ffmpeg", _uri, _mutex, BUFFER_SIZE)
io(_uri, AVIO_FLAG_READ)
{ {
seekable = (io->seekable & AVIO_SEEKABLE_NORMAL) != 0; Start();
size = io.GetSize();
/* hack to make MPD select the "ffmpeg" decoder plugin
- since avio.h doesn't tell us the MIME type of the
resource, we can't select a decoder plugin, but the
"ffmpeg" plugin is quite good at auto-detection */
SetMimeType("audio/x-mpd-ffmpeg");
SetReady();
} }
/* virtual methods from InputStream */ ~FfmpegInputStream() noexcept override {
[[nodiscard]] bool IsEOF() const noexcept override; Stop();
size_t Read(std::unique_lock<Mutex> &lock, }
std::span<std::byte> dest) override;
void Seek(std::unique_lock<Mutex> &lock, /* virtual methods from ThreadInputStream */
offset_type offset) override; void Open() override;
std::size_t ThreadRead(std::span<std::byte> dest) override;
void ThreadSeek(offset_type offset) override;
void Close() noexcept override {
io = {};
}
}; };
[[gnu::const]] [[gnu::const]]
@ -89,38 +88,31 @@ input_ffmpeg_open(const char *uri,
return std::make_unique<FfmpegInputStream>(uri, mutex); return std::make_unique<FfmpegInputStream>(uri, mutex);
} }
size_t void
FfmpegInputStream::Read(std::unique_lock<Mutex> &, FfmpegInputStream::Open()
std::span<std::byte> dest)
{ {
size_t result; io = {GetURI(), AVIO_FLAG_READ};
{ seekable = (io->seekable & AVIO_SEEKABLE_NORMAL) != 0;
const ScopeUnlock unlock(mutex); size = io.GetSize();
result = io.Read(dest);
}
offset += result; /* hack to make MPD select the "ffmpeg" decoder plugin - since
return (size_t)result; avio.h doesn't tell us the MIME type of the resource, we
can't select a decoder plugin, but the "ffmpeg" plugin is
quite good at auto-detection */
SetMimeType("audio/x-mpd-ffmpeg");
} }
bool std::size_t
FfmpegInputStream::IsEOF() const noexcept FfmpegInputStream::ThreadRead(std::span<std::byte> dest)
{ {
return io.IsEOF(); return io.Read(dest);
} }
void void
FfmpegInputStream::Seek(std::unique_lock<Mutex> &, offset_type new_offset) FfmpegInputStream::ThreadSeek(offset_type new_offset)
{ {
uint64_t result; io.Seek(new_offset);
{
const ScopeUnlock unlock(mutex);
result = io.Seek(new_offset);
}
offset = result;
} }
const InputPlugin input_plugin_ffmpeg = { const InputPlugin input_plugin_ffmpeg = {