Switching to Av libs to handle cover pictures
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include <boost/array.hpp>
|
#include <boost/array.hpp>
|
||||||
|
|
||||||
|
namespace Av
|
||||||
|
{
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
AvError::to_str(void) const
|
AvError::to_str(void) const
|
||||||
{
|
{
|
||||||
@@ -27,3 +30,5 @@ void AvInit()
|
|||||||
av_register_all();
|
av_register_all();
|
||||||
std::cout << "AVCDOEC VERSION = " << avcodec_version() << std::endl;
|
std::cout << "AVCDOEC VERSION = " << avcodec_version() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Av
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ extern "C" {
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
namespace Av
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
void AvInit();
|
void AvInit();
|
||||||
|
|
||||||
@@ -40,5 +43,6 @@ class AvError
|
|||||||
int _errnum;
|
int _errnum;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Av
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -96,4 +96,22 @@ InputFormatContext::getMetadata(void)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputFormatContext::getPictures(std::vector< std::vector<unsigned char> >& pictures) const
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < native()->nb_streams; ++i)
|
||||||
|
{
|
||||||
|
if (native()->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC)
|
||||||
|
{
|
||||||
|
std::cout << "Found album art..." << std::endl;
|
||||||
|
AVPacket pkt = native()->streams[i]->attached_pic;
|
||||||
|
|
||||||
|
std::vector<unsigned char> data;
|
||||||
|
std::copy(pkt.data, pkt.data + pkt.size, std::back_inserter(data));
|
||||||
|
|
||||||
|
pictures.push_back( data );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} //namespace Av
|
} //namespace Av
|
||||||
|
|||||||
@@ -25,11 +25,15 @@ class InputFormatContext : public FormatContext
|
|||||||
// Scan file
|
// Scan file
|
||||||
void findStreamInfo();
|
void findStreamInfo();
|
||||||
|
|
||||||
std::vector<Stream> getStreams(void);
|
|
||||||
|
|
||||||
bool getBestStreamIdx(enum AVMediaType type, Stream::Idx& idx);
|
// Get attached pictures
|
||||||
|
void getPictures(std::vector< std::vector<unsigned char> >& pictures) const;
|
||||||
|
|
||||||
std::size_t getDurationSecs() const;
|
// Get the streams
|
||||||
|
std::vector<Stream> getStreams(void);
|
||||||
|
|
||||||
|
bool getBestStreamIdx(enum AVMediaType type, Stream::Idx& idx);
|
||||||
|
std::size_t getDurationSecs() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::filesystem::path _path;
|
boost::filesystem::path _path;
|
||||||
|
|||||||
@@ -23,4 +23,10 @@ Stream::getMetadata(void)
|
|||||||
return Dictionary(_stream->metadata);
|
return Dictionary(_stream->metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Stream::hasAttachedPic(void) const
|
||||||
|
{
|
||||||
|
return (_stream->disposition & AV_DISPOSITION_ATTACHED_PIC);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Av
|
} // namespace Av
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class Stream
|
|||||||
|
|
||||||
// Idx getIdx() const { return _stream->index; }
|
// Idx getIdx() const { return _stream->index; }
|
||||||
|
|
||||||
|
bool hasAttachedPic(void) const;
|
||||||
Dictionary getMetadata(void);
|
Dictionary getMetadata(void);
|
||||||
CodecContext getCodecContext(void);
|
CodecContext getCodecContext(void);
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -22,31 +22,31 @@ Wt::WApplication *createApplication(const Wt::WEnvironment& env)
|
|||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Av::AvInit();
|
||||||
|
Transcode::AvConvTranscoder::init();
|
||||||
|
|
||||||
// std::locale::global(std::locale(""));
|
// std::locale::global(std::locale(""));
|
||||||
MetaData::AvFormat metadataParser;
|
MetaData::AvFormat metadataParser;
|
||||||
// MetaData::Extractor metadataParser;
|
// MetaData::Extractor metadataParser;
|
||||||
|
|
||||||
Transcode::AvConvTranscoder::init();
|
|
||||||
|
|
||||||
// Set up the long living database session
|
// Set up the long living database session
|
||||||
Database database("test.db", metadataParser);
|
Database database("test.db", metadataParser);
|
||||||
|
|
||||||
// database.watchDirectory( WatchedDirectory("/storage/common/Media/Son", WatchedDirectory::Audio ));
|
// database.watchDirectory( WatchedDirectory("/storage/common/Media/Son", WatchedDirectory::Audio ));
|
||||||
// database.watchDirectory(WatchedDirectory("/storage/common/Media/Son/Metal", WatchedDirectory::Audio));
|
database.watchDirectory(WatchedDirectory("/storage/common/Media/Son/Metal", WatchedDirectory::Audio));
|
||||||
// database.watchDirectory("/storage/common/Media/Son/Metal/Iced Earth/2004 - The Glorious Burden");
|
// database.watchDirectory("/storage/common/Media/Son/Metal/Iced Earth/2004 - The Glorious Burden");
|
||||||
// database.watchDirectory("/storage/common/Media/Son/Metal/System Of a Down");
|
// database.watchDirectory("/storage/common/Media/Son/Metal/System Of a Down");
|
||||||
// database.watchDirectory("/storage/common/Media/Son/Metal/Leprous");
|
// database.watchDirectory("/storage/common/Media/Son/Metal/Leprous");
|
||||||
// database.watchDirectory("/storage/common/Media/Son/Electro");
|
// database.watchDirectory("/storage/common/Media/Son/Electro");
|
||||||
// database.watchDirectory( WatchedDirectory("/storage/common/Media/Son/Electro", WatchedDirectory::Audio) );
|
// database.watchDirectory( WatchedDirectory("/storage/common/Media/Son/Electro", WatchedDirectory::Audio) );
|
||||||
// database.watchDirectory("/storage/common/Media/Son/Metal/Lacuna Coil");
|
// database.watchDirectory("/storage/common/Media/Son/Metal/Lacuna Coil");
|
||||||
// database.watchDirectory( WatchedDirectory("/storage/common/Media/Video", WatchedDirectory::Video) );
|
database.watchDirectory( WatchedDirectory("/storage/common/Media/Video", WatchedDirectory::Video) );
|
||||||
// database.watchDirectory( WatchedDirectory("/storage/common/Media/Video/Films", WatchedDirectory::Video) );
|
// database.watchDirectory( WatchedDirectory("/storage/common/Media/Video/Films", WatchedDirectory::Video) );
|
||||||
database.watchDirectory( WatchedDirectory("/storage/common/Media/Video/Series", WatchedDirectory::Video) );
|
// database.watchDirectory( WatchedDirectory("/storage/common/Media/Video/Series", WatchedDirectory::Video) );
|
||||||
|
|
||||||
std::cout << "Starting refresh..." << std::endl;
|
std::cout << "Starting refresh..." << std::endl;
|
||||||
// boost::thread refreshThread(boost::bind(&Database::refresh, &database));
|
boost::thread refreshThread(boost::bind(&Database::refresh, &database));
|
||||||
|
|
||||||
AvInit();
|
|
||||||
|
|
||||||
return Wt::WRun(argc, argv, &createApplication);
|
return Wt::WRun(argc, argv, &createApplication);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ AvConvTranscoder::AvConvTranscoder(const Parameters& parameters)
|
|||||||
oss << "avconv";
|
oss << "avconv";
|
||||||
|
|
||||||
// input Offset
|
// input Offset
|
||||||
oss << " -ss " << _parameters.getOffset().total_seconds(); // to be placed before '-i' to speed up seeking
|
if (_parameters.getOffset().total_seconds() > 0)
|
||||||
|
oss << " -ss " << _parameters.getOffset().total_seconds(); // to be placed before '-i' to speed up seeking
|
||||||
|
|
||||||
// Input file
|
// Input file
|
||||||
oss << " -i \"" << _parameters.getInputMediaFile().getPath().string() << "\"";
|
oss << " -i \"" << _parameters.getInputMediaFile().getPath().string() << "\"";
|
||||||
|
|||||||
@@ -33,28 +33,37 @@ InputMediaFile::InputMediaFile(const boost::filesystem::path& p)
|
|||||||
_duration = boost::posix_time::seconds(input.getDurationSecs() + 1);
|
_duration = boost::posix_time::seconds(input.getDurationSecs() + 1);
|
||||||
|
|
||||||
// Get input streams
|
// Get input streams
|
||||||
std::vector<Av::Stream> streams = input.getStreams();
|
std::vector<Av::Stream> avStreams = input.getStreams();
|
||||||
|
|
||||||
std::list<enum AVMediaType> types;
|
std::list<enum AVMediaType> avMediaTypes; // List of encountered streams
|
||||||
for (std::size_t streamId = 0; streamId < streams.size(); ++streamId)
|
for (std::size_t avStreamId = 0; avStreamId < avStreams.size(); ++avStreamId)
|
||||||
{
|
{
|
||||||
Stream::Type type;
|
Av::Stream& avStream(avStreams[avStreamId]);
|
||||||
|
Stream::Type type;
|
||||||
|
|
||||||
if (getStreamType(streams[streamId].getCodecContext().getType(), type))
|
if (getStreamType(avStream.getCodecContext().getType(), type))
|
||||||
{
|
{
|
||||||
types.push_back(streams[streamId].getCodecContext().getType());
|
// Reject Video stream hat are in fact cover arts
|
||||||
|
if (avStream.hasAttachedPic())
|
||||||
|
{
|
||||||
|
std::cout << "Rejecting stream since it is an attached picture!" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
_streams.push_back( Stream(streamId,
|
|
||||||
|
avMediaTypes.push_back(avStream.getCodecContext().getType());
|
||||||
|
|
||||||
|
_streams.push_back( Stream(avStreamId,
|
||||||
type,
|
type,
|
||||||
streams[streamId].getMetadata().get("language"), // TODO define somewhere else?
|
avStream.getMetadata().get("language"), // TODO define somewhere else?
|
||||||
streams[streamId].getCodecContext().getCodecDesc()
|
avStream.getCodecContext().getCodecDesc()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
types.unique();
|
avMediaTypes.unique();
|
||||||
// Scan for best streams
|
// Scan for best streams
|
||||||
BOOST_FOREACH(enum AVMediaType type, types)
|
BOOST_FOREACH(enum AVMediaType type, avMediaTypes)
|
||||||
{
|
{
|
||||||
Av::Stream::Idx index;
|
Av::Stream::Idx index;
|
||||||
|
|
||||||
@@ -68,6 +77,7 @@ InputMediaFile::InputMediaFile(const boost::filesystem::path& p)
|
|||||||
std::cerr << "Cannot find best stream for type " << type << std::endl;
|
std::cerr << "Cannot find best stream for type " << type << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input.getPictures( _coverPictures );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Stream>
|
std::vector<Stream>
|
||||||
@@ -82,6 +92,5 @@ InputMediaFile::getStreams(Stream::Type type) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Transcode
|
} // namespace Transcode
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ class InputMediaFile
|
|||||||
boost::filesystem::path getPath(void) const {return _path;}
|
boost::filesystem::path getPath(void) const {return _path;}
|
||||||
boost::posix_time::time_duration getDuration(void) const {return _duration;}
|
boost::posix_time::time_duration getDuration(void) const {return _duration;}
|
||||||
|
|
||||||
|
// Pictures
|
||||||
|
const std::vector< std::vector<unsigned char> >& getCoverPictures(void) const { return _coverPictures; }
|
||||||
|
|
||||||
// Stream handling
|
// Stream handling
|
||||||
std::vector<Stream> getStreams(Stream::Type type) const;
|
std::vector<Stream> getStreams(Stream::Type type) const;
|
||||||
const std::map<Stream::Type, Stream::Id>& getBestStreams(void) const {return _bestStreams;}
|
const std::map<Stream::Type, Stream::Id>& getBestStreams(void) const {return _bestStreams;}
|
||||||
@@ -43,6 +46,8 @@ class InputMediaFile
|
|||||||
|
|
||||||
std::vector<Stream> _streams;
|
std::vector<Stream> _streams;
|
||||||
std::map<Stream::Type, Stream::Id> _bestStreams;
|
std::map<Stream::Type, Stream::Id> _bestStreams;
|
||||||
|
|
||||||
|
std::vector< std::vector<unsigned char> > _coverPictures;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -49,15 +49,13 @@ AudioWidget::playTrack(boost::filesystem::path p)
|
|||||||
|
|
||||||
// Refresh cover
|
// Refresh cover
|
||||||
{
|
{
|
||||||
MetaData::Extractor parser;
|
const std::vector< std::vector<unsigned char> >& pictures = inputFile.getCoverPictures();
|
||||||
MetaData::GenericData cover;
|
|
||||||
if (parser.parseCover( p, cover)) {
|
|
||||||
std::cout << "Cover parsed!" << std::endl;
|
|
||||||
std::cout << "mime type = " << cover.mimeType << ", size = " << cover.data.size();
|
|
||||||
|
|
||||||
_imgResource->setMimeType(cover.mimeType);
|
|
||||||
_imgResource->setData(cover.data);
|
|
||||||
|
|
||||||
|
if (!pictures.empty())
|
||||||
|
{
|
||||||
|
std::cout << "Cover found!" << std::endl;
|
||||||
|
// _imgResource->setMimeType(cover.mimeType);
|
||||||
|
_imgResource->setData(pictures.front());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cout << "No cover found!" << std::endl;
|
std::cout << "No cover found!" << std::endl;
|
||||||
|
|||||||
Reference in New Issue
Block a user