From 14481d1e779a8ce5e8fa5eadbc0dfe0617e7028a Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 2 Sep 2015 20:56:12 +0200 Subject: [PATCH] Do not use exceptions when scan file error occurs --- TODO | 1 + src/av/InputFormatContext.cpp | 9 +- src/av/InputFormatContext.hpp | 2 +- src/database-updater/DatabaseUpdater.cpp | 4 +- src/metadata/AvFormat.cpp | 236 +++++++++++------------ src/metadata/AvFormat.hpp | 2 +- src/metadata/MetaData.hpp | 2 +- src/transcode/InputMediaFile.cpp | 11 +- 8 files changed, 133 insertions(+), 134 deletions(-) diff --git a/TODO b/TODO index eb58ef3d..c5e44bc0 100644 --- a/TODO +++ b/TODO @@ -14,6 +14,7 @@ - handle access rights problems (instead of aborting) - add a global play counter for tracks. This will help people to spot most popular files - rework the exception process in av/metadata/updater in case of bad files +- Use the WServer::post method to notify the end of the database scan? (with results?) [Metadata] - OGG metadata -> properly handle metadata nested in the audio stream diff --git a/src/av/InputFormatContext.cpp b/src/av/InputFormatContext.cpp index e455d9e7..448a6aed 100644 --- a/src/av/InputFormatContext.cpp +++ b/src/av/InputFormatContext.cpp @@ -87,14 +87,17 @@ InputFormatContext::getBestStreamIdx(AVMediaType type, Stream::Idx& index) } } -void +bool InputFormatContext::findStreamInfo(void) { AvError err = avformat_find_stream_info(native(), NULL); - if (err) { + if (err) + { LMS_LOG(MOD_AV, SEV_ERROR) << "Couldn't find stream information: " << err; - throw std::runtime_error("av_find_stream_info failed!"); + return false; } + + return true; } diff --git a/src/av/InputFormatContext.hpp b/src/av/InputFormatContext.hpp index 9385fdcc..17620287 100644 --- a/src/av/InputFormatContext.hpp +++ b/src/av/InputFormatContext.hpp @@ -47,7 +47,7 @@ class InputFormatContext : public FormatContext Dictionary getMetadata(void); // metadata access // Scan file - void findStreamInfo(); + bool findStreamInfo(); // Get attached pictures diff --git a/src/database-updater/DatabaseUpdater.cpp b/src/database-updater/DatabaseUpdater.cpp index 63239f2e..9470c9be 100644 --- a/src/database-updater/DatabaseUpdater.cpp +++ b/src/database-updater/DatabaseUpdater.cpp @@ -386,7 +386,9 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats) } MetaData::Items items; - _metadataParser.parse(file, items); + + if (!_metadataParser.parse(file, items)) + return; // We estimate this is a audio file if: // - we found a least one audio stream diff --git a/src/metadata/AvFormat.cpp b/src/metadata/AvFormat.cpp index 2ec53409..f4a75ad0 100644 --- a/src/metadata/AvFormat.cpp +++ b/src/metadata/AvFormat.cpp @@ -32,154 +32,146 @@ namespace MetaData { -void +bool AvFormat::parse(const boost::filesystem::path& p, Items& items) { - try { + Av::InputFormatContext input(p); - Av::InputFormatContext input(p); - input.findStreamInfo(); // needed by input.getDurationSecs + if (!input.findStreamInfo()) + return false; - std::map metadata; - input.getMetadata().get(metadata); + std::map metadata; + input.getMetadata().get(metadata); - // HACK or OGG files - // If we did not find tags, searched metadata in streams - if (metadata.empty()) + // HACK or OGG files + // If we did not find tags, searched metadata in streams + if (metadata.empty()) + { + // Get input streams + std::vector streams = input.getStreams(); + + BOOST_FOREACH(Av::Stream& stream, streams) { - // Get input streams - std::vector streams = input.getStreams(); + stream.getMetadata().get(metadata); - BOOST_FOREACH(Av::Stream& stream, streams) + if (!metadata.empty()) + break; + } + } + + + // Stream info + { + std::vector avStreams = input.getStreams(); + + std::vector audioStreams; + std::vector videoStreams; + std::vector subtitleStreams; + + BOOST_FOREACH(Av::Stream& avStream, avStreams) + { + switch(avStream.getCodecContext().getType()) { - stream.getMetadata().get(metadata); + case AVMEDIA_TYPE_VIDEO: + if (!avStream.hasAttachedPic()) + { + VideoStream stream; + stream.bitRate = avStream.getCodecContext().getBitRate(); + videoStreams.push_back(stream); + } + break; - if (!metadata.empty()) + case AVMEDIA_TYPE_AUDIO: + { + AudioStream stream; + stream.nbChannels = avStream.getCodecContext().getNbChannels(); + stream.bitRate = avStream.getCodecContext().getBitRate(); + audioStreams.push_back(stream); + } + break; + + case AVMEDIA_TYPE_SUBTITLE: + { + subtitleStreams.push_back( SubtitleStream() ); + } + break; + + default: break; } } + if (!videoStreams.empty()) + items.insert( std::make_pair(MetaData::Type::VideoStreams, videoStreams)); + if (!audioStreams.empty()) + items.insert( std::make_pair(MetaData::Type::AudioStreams, audioStreams)); + if (!subtitleStreams.empty()) + items.insert( std::make_pair(MetaData::Type::SubtitleStreams, subtitleStreams)); - // Stream info - { - std::vector avStreams = input.getStreams(); + } - std::vector audioStreams; - std::vector videoStreams; - std::vector subtitleStreams; + // Duration + items.insert( std::make_pair(MetaData::Type::Duration, boost::posix_time::time_duration( boost::posix_time::seconds( input.getDurationSecs() )) )); - BOOST_FOREACH(Av::Stream& avStream, avStreams) - { - switch(avStream.getCodecContext().getType()) - { - case AVMEDIA_TYPE_VIDEO: - if (!avStream.hasAttachedPic()) - { - VideoStream stream; - stream.bitRate = avStream.getCodecContext().getBitRate(); - videoStreams.push_back(stream); - } - break; - - case AVMEDIA_TYPE_AUDIO: - { - AudioStream stream; - stream.nbChannels = avStream.getCodecContext().getNbChannels(); - stream.bitRate = avStream.getCodecContext().getBitRate(); - audioStreams.push_back(stream); - } - break; - - case AVMEDIA_TYPE_SUBTITLE: - { - subtitleStreams.push_back( SubtitleStream() ); - } - break; - - default: - break; - } - } - - if (!videoStreams.empty()) - items.insert( std::make_pair(MetaData::Type::VideoStreams, videoStreams)); - if (!audioStreams.empty()) - items.insert( std::make_pair(MetaData::Type::AudioStreams, audioStreams)); - if (!subtitleStreams.empty()) - items.insert( std::make_pair(MetaData::Type::SubtitleStreams, subtitleStreams)); + // Cover + items.insert( std::make_pair(MetaData::Type::HasCover, input.getNbPictures() > 0)); + // Embedded MetaData + // Make sure to convert strings into UTF-8 + std::map::const_iterator it; + for (it = metadata.begin(); it != metadata.end(); ++it) + { + if (boost::iequals(it->first, "artist")) + items.insert( std::make_pair(MetaData::Type::Artist, string_trim( string_to_utf8(it->second)) )); + else if (boost::iequals(it->first, "album")) + items.insert( std::make_pair(MetaData::Type::Album, string_trim( string_to_utf8(it->second)) )); + else if (boost::iequals(it->first, "title")) + items.insert( std::make_pair(MetaData::Type::Title, string_trim( string_to_utf8(it->second)) )); + else if (boost::iequals(it->first, "track")) { + std::size_t number; + if (readAs(it->second, number)) + items.insert( std::make_pair(MetaData::Type::TrackNumber, number )); } - - // Duration - items.insert( std::make_pair(MetaData::Type::Duration, boost::posix_time::time_duration( boost::posix_time::seconds( input.getDurationSecs() )) )); - - // Cover - items.insert( std::make_pair(MetaData::Type::HasCover, input.getNbPictures() > 0)); - - // Embedded MetaData - // Make sure to convert strings into UTF-8 - std::map::const_iterator it; - for (it = metadata.begin(); it != metadata.end(); ++it) + else if (boost::iequals(it->first, "disc")) { - if (boost::iequals(it->first, "artist")) - items.insert( std::make_pair(MetaData::Type::Artist, string_trim( string_to_utf8(it->second)) )); - else if (boost::iequals(it->first, "album")) - items.insert( std::make_pair(MetaData::Type::Album, string_trim( string_to_utf8(it->second)) )); - else if (boost::iequals(it->first, "title")) - items.insert( std::make_pair(MetaData::Type::Title, string_trim( string_to_utf8(it->second)) )); - else if (boost::iequals(it->first, "track")) { - std::size_t number; - if (readAs(it->second, number)) - items.insert( std::make_pair(MetaData::Type::TrackNumber, number )); - } - else if (boost::iequals(it->first, "disc")) - { - std::size_t number; - if (readAs(it->second, number)) - items.insert( std::make_pair(MetaData::Type::DiscNumber, number )); - } - else if (boost::iequals(it->first, "date") + std::size_t number; + if (readAs(it->second, number)) + items.insert( std::make_pair(MetaData::Type::DiscNumber, number )); + } + else if (boost::iequals(it->first, "date") || boost::iequals(it->first, "year") || boost::iequals(it->first, "WM/Year")) - { - boost::posix_time::ptime p; - if (readAsPosixTime(it->second, p)) - items.insert( std::make_pair(MetaData::Type::Date, p)); - } - else if (boost::iequals(it->first, "TDOR") // Original release time (ID3v2 2.4) - || boost::iequals(it->first, "TORY")) // Original release year - { - boost::posix_time::ptime p; - if (readAsPosixTime(it->second, p)) - items.insert( std::make_pair(MetaData::Type::OriginalDate, p)); - } - else if (boost::iequals(it->first, "genre")) - { - std::list genres; - if (readList(it->second, ";,", genres)) - items.insert( std::make_pair(MetaData::Type::Genres, genres)); - - } - else if (boost::iequals(it->first, "MusicBrainz Artist Id")) - { - items.insert( std::make_pair(MetaData::Type::MusicBrainzArtistID, string_trim( string_to_utf8(it->second)) )); - } - else if (boost::iequals(it->first, "MusicBrainz Album Id")) - { - items.insert( std::make_pair(MetaData::Type::MusicBrainzAlbumID, string_trim( string_to_utf8(it->second)) )); - } -/* else - LMS_LOG(MOD_METADATA, SEV_DEBUG) << "key = " << it->first << ", value = " << it->second; -*/ + { + boost::posix_time::ptime p; + if (readAsPosixTime(it->second, p)) + items.insert( std::make_pair(MetaData::Type::Date, p)); } + else if (boost::iequals(it->first, "TDOR") // Original release time (ID3v2 2.4) + || boost::iequals(it->first, "TORY")) // Original release year + { + boost::posix_time::ptime p; + if (readAsPosixTime(it->second, p)) + items.insert( std::make_pair(MetaData::Type::OriginalDate, p)); + } + else if (boost::iequals(it->first, "genre")) + { + std::list genres; + if (readList(it->second, ";,", genres)) + items.insert( std::make_pair(MetaData::Type::Genres, genres)); - } - catch(std::exception &e) - { - LMS_LOG(MOD_METADATA, SEV_ERROR) << "Parsing of '" << p << "' failed!"; + } + else if (boost::iequals(it->first, "MusicBrainz Artist Id")) + { + items.insert( std::make_pair(MetaData::Type::MusicBrainzArtistID, string_trim( string_to_utf8(it->second)) )); + } + else if (boost::iequals(it->first, "MusicBrainz Album Id")) + { + items.insert( std::make_pair(MetaData::Type::MusicBrainzAlbumID, string_trim( string_to_utf8(it->second)) )); + } } + return true; } } // namespace MetaData diff --git a/src/metadata/AvFormat.hpp b/src/metadata/AvFormat.hpp index 46e1cb82..da5981b7 100644 --- a/src/metadata/AvFormat.hpp +++ b/src/metadata/AvFormat.hpp @@ -30,7 +30,7 @@ class AvFormat : public Parser { public: - void parse(const boost::filesystem::path& p, Items& items); + bool parse(const boost::filesystem::path& p, Items& items); private: diff --git a/src/metadata/MetaData.hpp b/src/metadata/MetaData.hpp index f872847b..bbd84002 100644 --- a/src/metadata/MetaData.hpp +++ b/src/metadata/MetaData.hpp @@ -71,7 +71,7 @@ namespace MetaData typedef std::shared_ptr pointer; - virtual void parse(const boost::filesystem::path& p, Items& items) = 0; + virtual bool parse(const boost::filesystem::path& p, Items& items) = 0; }; diff --git a/src/transcode/InputMediaFile.cpp b/src/transcode/InputMediaFile.cpp index 18045aa4..e8886499 100644 --- a/src/transcode/InputMediaFile.cpp +++ b/src/transcode/InputMediaFile.cpp @@ -19,7 +19,6 @@ #include -#include #include "logger/Logger.hpp" @@ -47,7 +46,9 @@ InputMediaFile::InputMediaFile(const boost::filesystem::path& p) : _path(p) { Av::InputFormatContext input(_path); - input.findStreamInfo(); + + if (!input.findStreamInfo()) + throw std::runtime_error("Cannot find stream info in file: " + p.string()); // Calculate estimated duration if (input.getDurationSecs()) @@ -83,7 +84,7 @@ InputMediaFile::InputMediaFile(const boost::filesystem::path& p) avMediaTypes.unique(); // Scan for best streams - BOOST_FOREACH(enum AVMediaType type, avMediaTypes) + for (enum AVMediaType type : avMediaTypes) { Av::Stream::Idx index; @@ -102,7 +103,7 @@ std::vector InputMediaFile::getStreams(Stream::Type type) const { std::vector res; - BOOST_FOREACH(const Stream& stream, _streams) + for (const Stream& stream : _streams) { if (stream.getType() == type) res.push_back(stream); @@ -113,7 +114,7 @@ InputMediaFile::getStreams(Stream::Type type) const const Stream& InputMediaFile::getStream(Stream::Id index) const { - BOOST_FOREACH(const Stream& stream, _streams) + for (const Stream& stream : _streams) { if (stream.getId() == index) return stream;