Commit de6d1664 authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

Add VideoTracks handling

parent 27f7cb09
......@@ -37,6 +37,9 @@ class IFile
virtual MoviePtr movie() = 0;
virtual bool setMovie( MoviePtr movie ) = 0;
virtual std::vector<std::shared_ptr<ILabel> > labels() = 0;
virtual bool addVideoTrack( const std::string& codec, unsigned int width,
unsigned int height, float fps ) = 0;
virtual bool videoTracks( std::vector<VideoTrackPtr>& tracks ) = 0;
};
#endif // IFILE_H
#ifndef IVIDEOTRACK_H
#define IVIDEOTRACK_H
#include "IMediaLibrary.h"
class IVideoTrack
{
public:
virtual ~IVideoTrack() {}
virtual unsigned int id() const = 0;
virtual const std::string& codec() const = 0;
virtual unsigned int width() const = 0;
virtual unsigned int height() const = 0;
virtual float fps() const = 0;
};
#endif // IVIDEOTRACK_H
......@@ -11,6 +11,8 @@ class IMetadataService;
class IMovie;
class IShow;
class IShowEpisode;
class IVideoTrack;
struct sqlite3;
typedef std::shared_ptr<IFile> FilePtr;
......@@ -20,6 +22,9 @@ typedef std::shared_ptr<IAlbumTrack> AlbumTrackPtr;
typedef std::shared_ptr<IShow> ShowPtr;
typedef std::shared_ptr<IShowEpisode> ShowEpisodePtr;
typedef std::shared_ptr<IMovie> MoviePtr;
typedef std::shared_ptr<IVideoTrack> VideoTrackPtr;
typedef std::weak_ptr<sqlite3> DBConnection;
#endif // TYPES_H
......@@ -30,6 +30,7 @@ list(APPEND SRC_LIST ${HEADERS_LIST}
ShowEpisode.cpp
Factory.cpp
Movie.cpp
VideoTrack.cpp
)
find_package(Sqlite3 REQUIRED)
......
......@@ -9,6 +9,7 @@
#include "Movie.h"
#include "ShowEpisode.h"
#include "SqliteTools.h"
#include "VideoTrack.h"
const std::string policy::FileTable::Name = "File";
const std::string policy::FileTable::CacheColumn = "mrl";
......@@ -136,6 +137,28 @@ bool File::setMovie( MoviePtr movie )
return true;
}
bool File::addVideoTrack(const std::string& codec, unsigned int width, unsigned int height, float fps)
{
static const std::string req = "INSERT INTO VideoTrackFileRelation VALUES(?, ?)";
auto track = VideoTrack::fetch( m_dbConnection, codec, width, height, fps );
if ( track == nullptr )
{
track = VideoTrack::create( m_dbConnection, codec, width, height, fps );
if ( track == nullptr )
return false;
}
return SqliteTools::executeRequest( m_dbConnection, req, track->id(), m_id );
}
bool File::videoTracks(std::vector<VideoTrackPtr>& tracks)
{
static const std::string req = "SELECT t.* FROM " + policy::VideoTrackTable::Name +
" t LEFT JOIN VideoTrackFileRelation vtfr ON vtfr.id_track = t.id_track"
" WHERE vtfr.id_file = ?";
return SqliteTools::fetchAll<VideoTrack>( m_dbConnection, req, tracks, m_id );
}
unsigned int File::id() const
{
return m_id;
......@@ -159,6 +182,17 @@ bool File::createTable( DBConnection connection )
"FOREIGN KEY (movie_id) REFERENCES " + policy::MovieTable::Name
+ "(id_movie) ON DELETE CASCADE"
")";
if ( SqliteTools::executeRequest( connection, req ) == false )
return false;
req = "CREATE TABLE IF NOT EXISTS VideoTrackFileRelation("
"id_track INTEGER,"
"id_file INTEGER,"
"PRIMARY KEY ( id_track, id_file ), "
"FOREIGN KEY ( id_track ) REFERENCES " + policy::VideoTrackTable::Name +
"(id_track) ON DELETE CASCADE,"
"FOREIGN KEY ( id_file ) REFERENCES " + policy::FileTable::Name
+ "(id_file) ON DELETE CASCADE"
")";
return SqliteTools::executeRequest( connection, req );
}
......
......@@ -58,6 +58,9 @@ class File : public IFile, public Cache<File, IFile, policy::FileTable, policy::
virtual const std::string& mrl() const;
virtual MoviePtr movie();
virtual bool setMovie( MoviePtr movie );
virtual bool addVideoTrack( const std::string& codec, unsigned int width,
unsigned int height, float fps );
virtual bool videoTracks( std::vector<VideoTrackPtr>& tracks );
private:
DBConnection m_dbConnection;
......
......@@ -11,6 +11,7 @@
#include "Movie.h"
#include "Show.h"
#include "ShowEpisode.h"
#include "VideoTrack.h"
MediaLibrary::MediaLibrary()
{
......@@ -25,6 +26,7 @@ MediaLibrary::~MediaLibrary()
Show::clear();
ShowEpisode::clear();
Movie::clear();
VideoTrack::clear();
}
bool MediaLibrary::initialize(const std::string& dbPath)
......@@ -42,7 +44,8 @@ bool MediaLibrary::initialize(const std::string& dbPath)
AlbumTrack::createTable( m_dbConnection ) &&
Show::createTable( m_dbConnection ) &&
ShowEpisode::createTable( m_dbConnection ) &&
Movie::createTable( m_dbConnection ) );
Movie::createTable( m_dbConnection ) ) &&
VideoTrack::createTable( m_dbConnection );
}
......
......@@ -43,6 +43,16 @@ struct Traits<std::string>
}
};
template <>
struct Traits<float>
{
static constexpr int
(*Bind)(sqlite3_stmt *, int, double) = &sqlite3_bind_double;
static constexpr double
(*Load)(sqlite3_stmt *, int) = &sqlite3_column_double;
};
class SqliteTools
{
private:
......
#include "VideoTrack.h"
const std::string policy::VideoTrackTable::Name = "VideoTrack";
const std::string policy::VideoTrackTable::CacheColumn = "id_track";
unsigned int VideoTrack::* const policy::VideoTrackTable::PrimaryKey = &VideoTrack::m_id;
VideoTrack::VideoTrack(DBConnection dbConnection, sqlite3_stmt* stmt)
: m_dbConnection( dbConnection )
, m_id( Traits<unsigned int>::Load( stmt, 0 ) )
, m_codec( Traits<std::string>::Load( stmt, 1 ) )
, m_width( Traits<unsigned int>::Load( stmt, 2 ) )
, m_height( Traits<unsigned int>::Load( stmt, 3 ) )
, m_fps( Traits<float>::Load( stmt, 4 ) )
{
}
VideoTrack::VideoTrack( const std::string& codec, unsigned int width, unsigned int height, float fps )
: m_id( 0 )
, m_codec( codec )
, m_width( width )
, m_height( height )
, m_fps( fps )
{
}
unsigned int VideoTrack::id() const
{
return m_id;
}
const std::string& VideoTrack::codec() const
{
return m_codec;
}
unsigned int VideoTrack::width() const
{
return m_width;
}
unsigned int VideoTrack::height() const
{
return m_height;
}
float VideoTrack::fps() const
{
return m_fps;
}
VideoTrackPtr VideoTrack::create( DBConnection dbConnection, const std::string &codec, unsigned int width, unsigned int height, float fps )
{
static const std::string req = "INSERT INTO " + policy::VideoTrackTable::Name
+ "(codec, width, height, fps) VALUES(?, ?, ?, ?)";
auto track = std::make_shared<VideoTrack>( codec, width, height, fps );
if ( _Cache::insert( dbConnection, track, req, codec, width, height, fps ) == false )
return nullptr;
track->m_dbConnection = dbConnection;
return track;
}
bool VideoTrack::createTable( DBConnection dbConnection )
{
static const std::string req = "CREATE TABLE IF NOT EXISTS " + policy::VideoTrackTable::Name
+ "(" +
policy::VideoTrackTable::CacheColumn + " INTEGER PRIMARY KEY AUTOINCREMENT,"
"codec TEXT,"
"width UNSIGNED INTEGER,"
"height UNSIGNED INTEGER,"
"fps FLOAT,"
"UNIQUE ( codec, width, height, fps ) ON CONFLICT FAIL"
")";
return SqliteTools::executeRequest( dbConnection, req );
}
VideoTrackPtr VideoTrack::fetch( DBConnection dbConnection, const std::string& codec, unsigned int width, unsigned int height, float fps )
{
static const std::string req = "SELECT * FROM " + policy::VideoTrackTable::Name +
" WHERE codec = ? AND width = ? AND height = ? AND fps = ?";
return SqliteTools::fetchOne<VideoTrack>( dbConnection, req, codec, width, height, fps );
}
#ifndef VIDEOTRACK_H
#define VIDEOTRACK_H
#include "Cache.h"
#include "IVideoTrack.h"
#include <sqlite3.h>
class VideoTrack;
namespace policy
{
struct VideoTrackTable
{
static const std::string Name;
static const std::string CacheColumn;
static unsigned int VideoTrack::* const PrimaryKey;
};
}
class VideoTrack : public IVideoTrack, public Cache<VideoTrack, IVideoTrack, policy::VideoTrackTable>
{
public:
VideoTrack( DBConnection dbConnection, sqlite3_stmt* stmt );
VideoTrack( const std::string& codec, unsigned int width, unsigned int height, float fps );
virtual unsigned int id() const;
virtual const std::string& codec() const;
virtual unsigned int width() const;
virtual unsigned int height() const;
virtual float fps() const;
static bool createTable( DBConnection dbConnection );
static VideoTrackPtr fetch( DBConnection dbConnection, const std::string& codec,
unsigned int width, unsigned int height, float fps );
static VideoTrackPtr create( DBConnection dbConnection, const std::string& codec,
unsigned int width, unsigned int height, float fps );
private:
DBConnection m_dbConnection;
unsigned int m_id;
const std::string m_codec;
const unsigned int m_width;
const unsigned int m_height;
const float m_fps;
private:
typedef Cache<VideoTrack, IVideoTrack, policy::VideoTrackTable> _Cache;
friend struct policy::VideoTrackTable;
};
#endif // VIDEOTRACK_H
......@@ -37,6 +37,7 @@ list(APPEND TEST_SRCS
Tests.cpp
Shows.cpp
Movies.cpp
VideoTracks.cpp
)
add_executable(unittest ${TEST_SRCS})
......
#include "gtest/gtest.h"
#include "IFile.h"
#include "IVideoTrack.h"
class VideoTracks : public testing::Test
{
public:
static std::unique_ptr<IMediaLibrary> ml;
protected:
virtual void SetUp()
{
ml.reset( MediaLibraryFactory::create() );
bool res = ml->initialize( "test.db" );
ASSERT_TRUE( res );
}
virtual void TearDown()
{
ml.reset();
unlink("test.db");
}
};
std::unique_ptr<IMediaLibrary> VideoTracks::ml;
TEST_F( VideoTracks, AddTrack )
{
auto f = ml->addFile( "file" );
bool res = f->addVideoTrack( "H264", 1920, 1080, 29.97 );
ASSERT_TRUE( res );
}
TEST_F( VideoTracks, FetchTracks )
{
auto f = ml->addFile( "file" );
f->addVideoTrack( "H264", 1920, 1080, 29.97 );
f->addVideoTrack( "VP80", 640, 480, 29.97 );
std::vector<VideoTrackPtr> ts;
bool res = f->videoTracks( ts );
ASSERT_TRUE( res );
ASSERT_EQ( ts.size(), 2u );
}
TEST_F( VideoTracks, CheckUnique )
{
auto f = ml->addFile( "file" );
f->addVideoTrack( "H264", 1920, 1080, 29.97 );
auto f2 = ml->addFile( "file2" );
f2->addVideoTrack( "H264", 1920, 1080, 29.97 );
std::vector<VideoTrackPtr> ts;
f->videoTracks( ts );
std::vector<VideoTrackPtr> ts2;
f2->videoTracks( ts2 );
ASSERT_EQ( ts.size(), 1u );
ASSERT_EQ( ts2.size(), 1u );
// Check that only 1 track has been created in DB
ASSERT_EQ( ts[0]->id(), ts2[0]->id() );
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment