diff --git a/database-updater/DatabaseUpdater.cpp b/database-updater/DatabaseUpdater.cpp index b5547182..6d196220 100644 --- a/database-updater/DatabaseUpdater.cpp +++ b/database-updater/DatabaseUpdater.cpp @@ -6,8 +6,6 @@ #include "database/MediaDirectory.hpp" #include "database/AudioTypes.hpp" -#include "transcode/InputMediaFile.hpp" - #include "Checksum.hpp" #include "DatabaseUpdater.hpp" @@ -44,12 +42,18 @@ Updater::process(void) } } + std::cout << "Audio changes = " << _result.audioStats.nbChanges() << std::endl; + std::cout << "Video changes = " << _result.videoStats.nbChanges() << std::endl; + + Database::MediaDirectorySettings::pointer settings = Database::MediaDirectorySettings::get(_db.getSession()); + boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); if (_result.audioStats.nbChanges() + _result.videoStats.nbChanges() > 0) - { - Database::MediaDirectorySettings::pointer settings = Database::MediaDirectorySettings::get(_db.getSession()); - settings.modify()->setLastUpdate(boost::posix_time::second_clock::local_time()); - } + settings.modify()->setLastUpdate(now); + + settings.modify()->setLastScan(now); + + transaction.commit(); } void @@ -71,7 +75,6 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats) } std::vector checksum; - /* Compute CRC */ computeCrc( file, checksum ); // Skip file if its checksum is still the same @@ -87,29 +90,30 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats) // We estimate this is a audio file if: // - we found a least one audio - // - there is no video stream // - the duration is not null - - Transcode::InputMediaFile mediaFile(file); -/* if (!mediaFile.getStreams( Transcode::Stream::Video ).empty()) - { - std::cerr << "Skipped '" << file << "' (estimated video)" << std::endl; - return; - } - else */if (mediaFile.getStreams( Transcode::Stream::Audio ).empty()) + if (items.find(MetaData::AudioStreams) == items.end() + || boost::any_cast >(items[MetaData::AudioStreams]).empty()) { std::cerr << "Skipped '" << file << "' (no audio stream found)" << std::endl; - return; - } - else if (mediaFile.getDuration().total_seconds() == 0) - { - std::cerr << "Skipped '" << file << "' (duration null!)" << std::endl; // If Track exists here, delete it! if (track) { track.remove(); stats.nbRemoved++; } + return; + } + if (items.find(MetaData::Duration) == items.end() + || boost::any_cast(items[MetaData::Duration]).total_seconds() == 0) + { + std::cerr << "Skipped '" << file << "' (no duration or duration 0)" << std::endl; + + // If Track exists here, delete it! + if (track) { + track.remove(); + stats.nbRemoved++; + } + return; } std::string title; @@ -157,9 +161,9 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats) typedef std::list GenreList; GenreList genreList; std::vector< Genre::pointer > genres; - if (items.find(MetaData::Genre) != items.end()) + if (items.find(MetaData::Genres) != items.end()) { - genreList = (boost::any_cast(items[MetaData::Genre])); + genreList = (boost::any_cast(items[MetaData::Genres])); BOOST_FOREACH(const std::string& genre, genreList) { Genre::pointer dbGenre ( Genre::getByName(_db.getSession(), genre) ); @@ -376,26 +380,27 @@ Updater::processVideoFile( const boost::filesystem::path& file) std::cout << "Video, parsing file " << file << std::endl; - // TODO try to open the video file and get info on it - Transcode::InputMediaFile mediaFile(file); + MetaData::Items items; + _metadataParser.parse(file, items); // We estimate this is a video if: // - we found a least one video stream // - the duration is not null - std::vector videoStreams(mediaFile.getStreams( Transcode::Stream::Video )); - if (videoStreams.empty()) + if (items.find(MetaData::VideoStreams) == items.end() + || boost::any_cast >(items[MetaData::VideoStreams]).empty()) { - std::cerr << "Skipped '" << file << "' (no video stream found!)" << std::endl; + std::cerr << "Skipped '" << file << "' (no video stream found)" << std::endl; - // If Path exist, delete it! + // If Track exists here, delete it! if (dbPath) dbPath.remove(); } - else if (mediaFile.getDuration().total_seconds() == 0) + else if (items.find(MetaData::Duration) == items.end() + || boost::any_cast(items[MetaData::Duration]).total_seconds() == 0) { - std::cerr << "Skipped '" << file << "' (duration null!)" << std::endl; + std::cerr << "Skipped '" << file << "' (no duration or duration 0)" << std::endl; - // If Path exist, delete it! + // If Track exists here, delete it! if (dbPath) dbPath.remove(); } @@ -423,7 +428,7 @@ Updater::processVideoFile( const boost::filesystem::path& file) assert(video); video.modify()->setName( file.filename().string() ); - video.modify()->setDuration( mediaFile.getDuration() ); + video.modify()->setDuration( boost::any_cast(items[MetaData::Duration]) ); } transaction.commit(); diff --git a/metadata/AvFormat.cpp b/metadata/AvFormat.cpp index e608a12f..c8b29eff 100644 --- a/metadata/AvFormat.cpp +++ b/metadata/AvFormat.cpp @@ -32,7 +32,8 @@ AvFormat::parse(const boost::filesystem::path& p, Items& items) // Get input streams std::vector streams = input.getStreams(); - BOOST_FOREACH(Av::Stream& stream, streams) { + BOOST_FOREACH(Av::Stream& stream, streams) + { stream.getMetadata().get(metadata); if (!metadata.empty()) @@ -40,10 +41,61 @@ AvFormat::parse(const boost::filesystem::path& p, Items& items) } } - std::cout << "Found " << metadata.size() << " tags!" << std::endl; + // 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()) + { + 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::VideoStreams, videoStreams)); + if (!audioStreams.empty()) + items.insert( std::make_pair(MetaData::AudioStreams, audioStreams)); + if (!subtitleStreams.empty()) + items.insert( std::make_pair(MetaData::SubtitleStreams, SubtitleStreams)); + + } + + // Duration items.insert( std::make_pair(MetaData::Duration, boost::posix_time::time_duration( boost::posix_time::seconds( input.getDurationSecs() )) )); + // Embedded MetaData // Make sure to convert strings into UTF-8 std::map::const_iterator it; for (it = metadata.begin(); it != metadata.end(); ++it) @@ -80,7 +132,7 @@ AvFormat::parse(const boost::filesystem::path& p, Items& items) { std::list genres; if (readList(it->second, ";,", genres)) - items.insert( std::make_pair(MetaData::Genre, genres)); + items.insert( std::make_pair(MetaData::Genres, genres)); } /* else diff --git a/metadata/MetaData.hpp b/metadata/MetaData.hpp index be38755c..1b1ea1ab 100644 --- a/metadata/MetaData.hpp +++ b/metadata/MetaData.hpp @@ -11,23 +11,42 @@ namespace MetaData enum Type { - Artist, - Title, - Album, - Genre, - Duration, - TrackNumber, - DiscNumber, - CreationTime, - Cover, + Artist, // string + Title, // string + Album, // string + Genres, // list + Duration, // boost::posix_time::time_duration + TrackNumber, // size_t + DiscNumber, // size_t + CreationTime, // boost::posix_time::ptime + Cover, // GenericData + AudioStreams, // vector + VideoStreams, // vector + SubtitleStreams, // vector }; - // Used for Cover + // Used by Cover struct GenericData { std::string mimeType; std::vector data; }; + // Used by Streams + struct AudioStream { + std::size_t nbChannels; + std::size_t bitRate; + }; + + struct VideoStream { + std::size_t bitRate; + }; + + struct SubtitleStream { + ; + }; + + // Type and associated data + // See enum Type's comments typedef std::map Items; class Parser