decoder/Plugin: allow scan_{file,stream}() to throw
Bug #915 is about an I/O exception thrown where none was allowed, leading to crash via std::terminate(). However, instead of catching and logging the error inside the decoder plugin, it should be able to propagate the I/O error to the MPD core, so MPD can avoid trying other decoder plugins. Closes https://github.com/MusicPlayerDaemon/MPD/issues/915
This commit is contained in:
parent
daefc61aa4
commit
bfdf13dca3
2
NEWS
2
NEWS
@ -7,6 +7,8 @@ ver 0.21.25 (not yet released)
|
|||||||
* decoder
|
* decoder
|
||||||
- opus: apply pre-skip and end trimming
|
- opus: apply pre-skip and end trimming
|
||||||
- opus: fix memory leak
|
- opus: fix memory leak
|
||||||
|
- opus: fix crash bug
|
||||||
|
- vorbis: fix crash bug
|
||||||
* output
|
* output
|
||||||
- osx: improve sample rate selection
|
- osx: improve sample rate selection
|
||||||
- osx: fix noise while stopping
|
- osx: fix noise while stopping
|
||||||
|
@ -79,17 +79,22 @@ Song::UpdateFile(Storage &storage) noexcept
|
|||||||
TagBuilder tag_builder;
|
TagBuilder tag_builder;
|
||||||
auto new_audio_format = AudioFormat::Undefined();
|
auto new_audio_format = AudioFormat::Undefined();
|
||||||
|
|
||||||
const auto path_fs = storage.MapFS(relative_uri.c_str());
|
try {
|
||||||
if (path_fs.IsNull()) {
|
const auto path_fs = storage.MapFS(relative_uri.c_str());
|
||||||
const auto absolute_uri =
|
if (path_fs.IsNull()) {
|
||||||
storage.MapUTF8(relative_uri.c_str());
|
const auto absolute_uri =
|
||||||
if (!tag_stream_scan(absolute_uri.c_str(), tag_builder,
|
storage.MapUTF8(relative_uri.c_str());
|
||||||
&new_audio_format))
|
if (!tag_stream_scan(absolute_uri.c_str(), tag_builder,
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
if (!ScanFileTagsWithGeneric(path_fs, tag_builder,
|
|
||||||
&new_audio_format))
|
&new_audio_format))
|
||||||
return false;
|
return false;
|
||||||
|
} else {
|
||||||
|
if (!ScanFileTagsWithGeneric(path_fs, tag_builder,
|
||||||
|
&new_audio_format))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
// TODO: log or propagate I/O errors?
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtime = info.mtime;
|
mtime = info.mtime;
|
||||||
@ -153,8 +158,14 @@ DetachedSong::LoadFile(Path path) noexcept
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
TagBuilder tag_builder;
|
TagBuilder tag_builder;
|
||||||
if (!ScanFileTagsWithGeneric(path, tag_builder))
|
|
||||||
|
try {
|
||||||
|
if (!ScanFileTagsWithGeneric(path, tag_builder))
|
||||||
|
return false;
|
||||||
|
} catch (...) {
|
||||||
|
// TODO: log or propagate I/O errors?
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
mtime = fi.GetModificationTime();
|
mtime = fi.GetModificationTime();
|
||||||
tag_builder.Commit(tag);
|
tag_builder.Commit(tag);
|
||||||
@ -173,8 +184,14 @@ DetachedSong::Update() noexcept
|
|||||||
return LoadFile(path_fs);
|
return LoadFile(path_fs);
|
||||||
} else if (IsRemote()) {
|
} else if (IsRemote()) {
|
||||||
TagBuilder tag_builder;
|
TagBuilder tag_builder;
|
||||||
if (!tag_stream_scan(uri.c_str(), tag_builder))
|
|
||||||
|
try {
|
||||||
|
if (!tag_stream_scan(uri.c_str(), tag_builder))
|
||||||
|
return false;
|
||||||
|
} catch (...) {
|
||||||
|
// TODO: log or propagate I/O errors?
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
mtime = std::chrono::system_clock::time_point::min();
|
mtime = std::chrono::system_clock::time_point::min();
|
||||||
tag_builder.Commit(tag);
|
tag_builder.Commit(tag);
|
||||||
|
@ -47,11 +47,11 @@ public:
|
|||||||
handler(_handler),
|
handler(_handler),
|
||||||
is(nullptr) {}
|
is(nullptr) {}
|
||||||
|
|
||||||
bool ScanFile(const DecoderPlugin &plugin) noexcept {
|
bool ScanFile(const DecoderPlugin &plugin) {
|
||||||
return plugin.ScanFile(path_fs, handler);
|
return plugin.ScanFile(path_fs, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScanStream(const DecoderPlugin &plugin) noexcept {
|
bool ScanStream(const DecoderPlugin &plugin) {
|
||||||
if (plugin.scan_stream == nullptr)
|
if (plugin.scan_stream == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -73,14 +73,14 @@ public:
|
|||||||
return plugin.ScanStream(*is, handler);
|
return plugin.ScanStream(*is, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scan(const DecoderPlugin &plugin) noexcept {
|
bool Scan(const DecoderPlugin &plugin) {
|
||||||
return plugin.SupportsSuffix(suffix) &&
|
return plugin.SupportsSuffix(suffix) &&
|
||||||
(ScanFile(plugin) || ScanStream(plugin));
|
(ScanFile(plugin) || ScanStream(plugin));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ScanFileTagsNoGeneric(Path path_fs, TagHandler &handler) noexcept
|
ScanFileTagsNoGeneric(Path path_fs, TagHandler &handler)
|
||||||
{
|
{
|
||||||
assert(!path_fs.IsNull());
|
assert(!path_fs.IsNull());
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ ScanFileTagsNoGeneric(Path path_fs, TagHandler &handler) noexcept
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
ScanFileTagsWithGeneric(Path path, TagBuilder &builder,
|
ScanFileTagsWithGeneric(Path path, TagBuilder &builder,
|
||||||
AudioFormat *audio_format) noexcept
|
AudioFormat *audio_format)
|
||||||
{
|
{
|
||||||
FullTagHandler h(builder, audio_format);
|
FullTagHandler h(builder, audio_format);
|
||||||
|
|
||||||
|
@ -30,22 +30,26 @@ class TagBuilder;
|
|||||||
* but does not fall back to generic scanners (APE and ID3) if no tags
|
* but does not fall back to generic scanners (APE and ID3) if no tags
|
||||||
* were found (but the file was recognized).
|
* were found (but the file was recognized).
|
||||||
*
|
*
|
||||||
|
* Throws on I/O error.
|
||||||
|
*
|
||||||
* @return true if the file was recognized (even if no metadata was
|
* @return true if the file was recognized (even if no metadata was
|
||||||
* found)
|
* found)
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
ScanFileTagsNoGeneric(Path path, TagHandler &handler) noexcept;
|
ScanFileTagsNoGeneric(Path path, TagHandler &handler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scan the tags of a song file. Invokes matching decoder plugins,
|
* Scan the tags of a song file. Invokes matching decoder plugins,
|
||||||
* and falls back to generic scanners (APE and ID3) if no tags were
|
* and falls back to generic scanners (APE and ID3) if no tags were
|
||||||
* found (but the file was recognized).
|
* found (but the file was recognized).
|
||||||
*
|
*
|
||||||
|
* Throws on I/O error.
|
||||||
|
*
|
||||||
* @return true if the file was recognized (even if no metadata was
|
* @return true if the file was recognized (even if no metadata was
|
||||||
* found)
|
* found)
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
ScanFileTagsWithGeneric(Path path, TagBuilder &builder,
|
ScanFileTagsWithGeneric(Path path, TagBuilder &builder,
|
||||||
AudioFormat *audio_format=nullptr) noexcept;
|
AudioFormat *audio_format=nullptr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,7 +45,7 @@ CheckDecoderPlugin(const DecoderPlugin &plugin,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
tag_stream_scan(InputStream &is, TagHandler &handler) noexcept
|
tag_stream_scan(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
assert(is.IsReady());
|
assert(is.IsReady());
|
||||||
|
|
||||||
@ -73,19 +73,17 @@ tag_stream_scan(InputStream &is, TagHandler &handler) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
tag_stream_scan(const char *uri, TagHandler &handler) noexcept
|
tag_stream_scan(const char *uri, TagHandler &handler)
|
||||||
try {
|
{
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
|
|
||||||
auto is = InputStream::OpenReady(uri, mutex);
|
auto is = InputStream::OpenReady(uri, mutex);
|
||||||
return tag_stream_scan(*is, handler);
|
return tag_stream_scan(*is, handler);
|
||||||
} catch (const std::exception &e) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
tag_stream_scan(InputStream &is, TagBuilder &builder,
|
tag_stream_scan(InputStream &is, TagBuilder &builder,
|
||||||
AudioFormat *audio_format) noexcept
|
AudioFormat *audio_format)
|
||||||
{
|
{
|
||||||
assert(is.IsReady());
|
assert(is.IsReady());
|
||||||
|
|
||||||
@ -102,12 +100,10 @@ tag_stream_scan(InputStream &is, TagBuilder &builder,
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
tag_stream_scan(const char *uri, TagBuilder &builder,
|
tag_stream_scan(const char *uri, TagBuilder &builder,
|
||||||
AudioFormat *audio_format) noexcept
|
AudioFormat *audio_format)
|
||||||
try {
|
{
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
|
|
||||||
auto is = InputStream::OpenReady(uri, mutex);
|
auto is = InputStream::OpenReady(uri, mutex);
|
||||||
return tag_stream_scan(*is, builder, audio_format);
|
return tag_stream_scan(*is, builder, audio_format);
|
||||||
} catch (const std::exception &e) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
@ -29,29 +29,39 @@ class TagBuilder;
|
|||||||
* Scan the tags of an #InputStream. Invokes matching decoder
|
* Scan the tags of an #InputStream. Invokes matching decoder
|
||||||
* plugins, but does not invoke the special "APE" and "ID3" scanners.
|
* plugins, but does not invoke the special "APE" and "ID3" scanners.
|
||||||
*
|
*
|
||||||
|
* Throws on I/O error.
|
||||||
|
*
|
||||||
* @return true if the file was recognized (even if no metadata was
|
* @return true if the file was recognized (even if no metadata was
|
||||||
* found)
|
* found)
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
tag_stream_scan(InputStream &is, TagHandler &handler) noexcept;
|
tag_stream_scan(InputStream &is, TagHandler &handler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws on I/O error.
|
||||||
|
*/
|
||||||
bool
|
bool
|
||||||
tag_stream_scan(const char *uri, TagHandler &handler) noexcept;
|
tag_stream_scan(const char *uri, TagHandler &handler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scan the tags of an #InputStream. Invokes matching decoder
|
* Scan the tags of an #InputStream. Invokes matching decoder
|
||||||
* plugins, and falls back to generic scanners (APE and ID3) if no
|
* plugins, and falls back to generic scanners (APE and ID3) if no
|
||||||
* tags were found (but the file was recognized).
|
* tags were found (but the file was recognized).
|
||||||
*
|
*
|
||||||
|
* Throws on I/O error.
|
||||||
|
*
|
||||||
* @return true if the file was recognized (even if no metadata was
|
* @return true if the file was recognized (even if no metadata was
|
||||||
* found)
|
* found)
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
tag_stream_scan(InputStream &is, TagBuilder &builder,
|
tag_stream_scan(InputStream &is, TagBuilder &builder,
|
||||||
AudioFormat *audio_format=nullptr) noexcept;
|
AudioFormat *audio_format=nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws on I/O error.
|
||||||
|
*/
|
||||||
bool
|
bool
|
||||||
tag_stream_scan(const char *uri, TagBuilder &builder,
|
tag_stream_scan(const char *uri, TagBuilder &builder,
|
||||||
AudioFormat *audio_format=nullptr) noexcept;
|
AudioFormat *audio_format=nullptr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -67,18 +67,22 @@ struct DecoderPlugin {
|
|||||||
void (*file_decode)(DecoderClient &client, Path path_fs);
|
void (*file_decode)(DecoderClient &client, Path path_fs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scan metadata of a file.
|
* Scan metadata of a file.
|
||||||
|
*
|
||||||
|
* Throws on I/O error.
|
||||||
*
|
*
|
||||||
* @return false if the operation has failed
|
* @return false if the file was not recognized
|
||||||
*/
|
*/
|
||||||
bool (*scan_file)(Path path_fs, TagHandler &handler) noexcept;
|
bool (*scan_file)(Path path_fs, TagHandler &handler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scan metadata of a file.
|
* Scan metadata of a stream.
|
||||||
|
*
|
||||||
|
* Throws on I/O error.
|
||||||
*
|
*
|
||||||
* @return false if the operation has failed
|
* @return false if the stream was not recognized
|
||||||
*/
|
*/
|
||||||
bool (*scan_stream)(InputStream &is, TagHandler &handler) noexcept;
|
bool (*scan_stream)(InputStream &is, TagHandler &handler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a "virtual" filename for subtracks in
|
* @brief Return a "virtual" filename for subtracks in
|
||||||
@ -135,7 +139,7 @@ struct DecoderPlugin {
|
|||||||
* Read the tag of a file.
|
* Read the tag of a file.
|
||||||
*/
|
*/
|
||||||
template<typename P>
|
template<typename P>
|
||||||
bool ScanFile(P path_fs, TagHandler &handler) const noexcept {
|
bool ScanFile(P path_fs, TagHandler &handler) const {
|
||||||
return scan_file != nullptr
|
return scan_file != nullptr
|
||||||
? scan_file(path_fs, handler)
|
? scan_file(path_fs, handler)
|
||||||
: false;
|
: false;
|
||||||
@ -144,7 +148,7 @@ struct DecoderPlugin {
|
|||||||
/**
|
/**
|
||||||
* Read the tag of a stream.
|
* Read the tag of a stream.
|
||||||
*/
|
*/
|
||||||
bool ScanStream(InputStream &is, TagHandler &handler) const noexcept {
|
bool ScanStream(InputStream &is, TagHandler &handler) const {
|
||||||
return scan_stream != nullptr
|
return scan_stream != nullptr
|
||||||
? scan_stream(is, handler)
|
? scan_stream(is, handler)
|
||||||
: false;
|
: false;
|
||||||
|
@ -241,7 +241,7 @@ audiofile_stream_decode(DecoderClient &client, InputStream &is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
audiofile_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
audiofile_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
if (!is.IsSeekable() || !is.KnownSize())
|
if (!is.IsSeekable() || !is.KnownSize())
|
||||||
return false;
|
return false;
|
||||||
|
@ -449,7 +449,7 @@ dsdiff_stream_decode(DecoderClient &client, InputStream &is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
dsdiff_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
dsdiff_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
DsdiffMetaData metadata;
|
DsdiffMetaData metadata;
|
||||||
DsdiffChunkHeader chunk_header;
|
DsdiffChunkHeader chunk_header;
|
||||||
|
@ -326,7 +326,7 @@ dsf_stream_decode(DecoderClient &client, InputStream &is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
dsf_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
dsf_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
/* check DSF metadata */
|
/* check DSF metadata */
|
||||||
DsfMetaData metadata;
|
DsfMetaData metadata;
|
||||||
|
@ -414,7 +414,7 @@ faad_stream_decode(DecoderClient &client, InputStream &is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
faad_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
faad_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
auto result = faad_get_file_time(is);
|
auto result = faad_get_file_time(is);
|
||||||
if (!result.first)
|
if (!result.first)
|
||||||
|
@ -646,8 +646,7 @@ ffmpeg_decode(DecoderClient &client, InputStream &input)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
FfmpegScanStream(AVFormatContext &format_context,
|
FfmpegScanStream(AVFormatContext &format_context, TagHandler &handler)
|
||||||
TagHandler &handler) noexcept
|
|
||||||
{
|
{
|
||||||
const int find_result =
|
const int find_result =
|
||||||
avformat_find_stream_info(&format_context, nullptr);
|
avformat_find_stream_info(&format_context, nullptr);
|
||||||
@ -680,7 +679,7 @@ FfmpegScanStream(AVFormatContext &format_context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
ffmpeg_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
ffmpeg_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
AvioStream stream(nullptr, is);
|
AvioStream stream(nullptr, is);
|
||||||
if (!stream.Open())
|
if (!stream.Open())
|
||||||
|
@ -69,7 +69,7 @@ flac_write_cb(const FLAC__StreamDecoder *dec, const FLAC__Frame *frame,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
flac_scan_file(Path path_fs, TagHandler &handler) noexcept
|
flac_scan_file(Path path_fs, TagHandler &handler)
|
||||||
{
|
{
|
||||||
FlacMetadataChain chain;
|
FlacMetadataChain chain;
|
||||||
if (!chain.Read(NarrowPath(path_fs))) {
|
if (!chain.Read(NarrowPath(path_fs))) {
|
||||||
@ -84,7 +84,7 @@ flac_scan_file(Path path_fs, TagHandler &handler) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
flac_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
flac_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
FlacMetadataChain chain;
|
FlacMetadataChain chain;
|
||||||
if (!chain.Read(is)) {
|
if (!chain.Read(is)) {
|
||||||
@ -313,7 +313,7 @@ oggflac_init(gcc_unused const ConfigBlock &block)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
oggflac_scan_file(Path path_fs, TagHandler &handler) noexcept
|
oggflac_scan_file(Path path_fs, TagHandler &handler)
|
||||||
{
|
{
|
||||||
FlacMetadataChain chain;
|
FlacMetadataChain chain;
|
||||||
if (!chain.ReadOgg(NarrowPath(path_fs))) {
|
if (!chain.ReadOgg(NarrowPath(path_fs))) {
|
||||||
@ -328,7 +328,7 @@ oggflac_scan_file(Path path_fs, TagHandler &handler) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
oggflac_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
oggflac_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
FlacMetadataChain chain;
|
FlacMetadataChain chain;
|
||||||
if (!chain.ReadOgg(is)) {
|
if (!chain.ReadOgg(is)) {
|
||||||
|
@ -1051,7 +1051,7 @@ MadDecoder::RunScan(TagHandler &handler) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
mad_decoder_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
mad_decoder_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
MadDecoder data(nullptr, is);
|
MadDecoder data(nullptr, is);
|
||||||
return data.RunScan(handler);
|
return data.RunScan(handler);
|
||||||
|
@ -275,7 +275,7 @@ mpcdec_get_file_duration(InputStream &is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
mpcdec_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
mpcdec_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
const auto duration = mpcdec_get_file_duration(is);
|
const auto duration = mpcdec_get_file_duration(is);
|
||||||
if (duration.IsNegative())
|
if (duration.IsNegative())
|
||||||
|
@ -424,7 +424,7 @@ VisitOpusDuration(InputStream &is, OggSyncState &sync, OggStreamState &stream,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
mpd_opus_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
mpd_opus_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
InputStreamReader reader(is);
|
InputStreamReader reader(is);
|
||||||
OggSyncState oy(reader);
|
OggSyncState oy(reader);
|
||||||
|
@ -267,7 +267,7 @@ static constexpr struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sndfile_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
sndfile_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
SF_INFO info;
|
SF_INFO info;
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ VisitVorbisDuration(InputStream &is,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
vorbis_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
vorbis_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
/* initialize libogg */
|
/* initialize libogg */
|
||||||
|
|
||||||
|
@ -614,7 +614,7 @@ wavpack_scan_file(Path path_fs, TagHandler &handler) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
wavpack_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
wavpack_scan_stream(InputStream &is, TagHandler &handler)
|
||||||
{
|
{
|
||||||
WavpackInput isp(nullptr, is);
|
WavpackInput isp(nullptr, is);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user