adapt Media-Access (+Mock) to include an overall Duration
This commit is contained in:
parent
46c9811184
commit
a207a9f003
10 changed files with 195 additions and 134 deletions
|
|
@ -28,30 +28,26 @@
|
|||
using util::isnil;
|
||||
using lumiera::error::Invalid;
|
||||
|
||||
namespace backend_interface
|
||||
{
|
||||
namespace backend {
|
||||
|
||||
/** storage for the SingletonFactory
|
||||
* (actually a lumiera::test::MockInjector) */
|
||||
Singleton<MediaAccessFacade> MediaAccessFacade::instance;
|
||||
|
||||
|
||||
typedef MediaAccessFacade::FileHandle FileHandle;
|
||||
typedef MediaAccessFacade::ChanHandle ChanHandle;
|
||||
|
||||
FileHandle
|
||||
MediaAccessFacade::queryFile (const char* name) throw(Invalid)
|
||||
MediaDesc&
|
||||
MediaAccessFacade::queryFile (string const& name) const
|
||||
{
|
||||
if (isnil (name))
|
||||
throw Invalid ("empty filename passed to MediaAccessFacade.");
|
||||
|
||||
UNIMPLEMENTED ("delegate to backend: query accessability of file");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ChanDesc
|
||||
MediaAccessFacade::queryChannel (FileHandle fhandle, uint chanNo) throw()
|
||||
MediaAccessFacade::queryChannel (MediaDesc& mHandle, uint chanNo) const
|
||||
{
|
||||
UNIMPLEMENTED ("delegate to backend: query channel information");
|
||||
ChanDesc nix;
|
||||
|
|
@ -60,4 +56,4 @@ namespace backend_interface
|
|||
|
||||
|
||||
|
||||
} // namespace backend_interface
|
||||
} // namespace backend
|
||||
|
|
|
|||
|
|
@ -25,13 +25,20 @@
|
|||
#define BACKEND_INTERFACE_MEDIAACCESSFACADE_H
|
||||
|
||||
|
||||
#include "lib/singleton.hpp"
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/singleton.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
namespace backend_interface {
|
||||
namespace backend {
|
||||
|
||||
using lib::time::Duration;
|
||||
using std::string;
|
||||
|
||||
struct MediaDesc;
|
||||
struct ChanDesc;
|
||||
|
||||
|
||||
|
|
@ -42,24 +49,26 @@ namespace backend_interface {
|
|||
* Implementation delegating to the actual backend functions.
|
||||
*
|
||||
* convention: data passed by pointer is owned by the originator;
|
||||
* it should be copied if needed byond the control flow
|
||||
* it should be copied if needed beyond the control flow
|
||||
* of the invoked function.
|
||||
*/
|
||||
struct MediaAccessFacade
|
||||
class MediaAccessFacade
|
||||
{
|
||||
typedef void* FileHandle;
|
||||
public:
|
||||
typedef void* ChanHandle;
|
||||
|
||||
static Singleton<MediaAccessFacade> instance;
|
||||
|
||||
/** request for testing the denoted files accessibility
|
||||
* @param name path and filename of the media file.
|
||||
* @throw invalid when passing empty filename
|
||||
* @throw error::Invalid when passing empty filename,
|
||||
* or in case the media file is inaccessible
|
||||
* or otherwise inappropriate.
|
||||
* @return opaque handle usable for querying channel
|
||||
* information from this file, NULL if the
|
||||
* file is not accessible.
|
||||
*/
|
||||
virtual FileHandle queryFile (const char* name) throw(lumiera::error::Invalid);
|
||||
virtual MediaDesc& queryFile (string const& name) const;
|
||||
|
||||
/** request for information about the n-th channel
|
||||
* of the file referred by FileHandle.
|
||||
|
|
@ -67,12 +76,31 @@ namespace backend_interface {
|
|||
* the file doesn't contain this much channels.
|
||||
* @todo throw or return NULL-ChanDesc if Filehandle is invalid?
|
||||
*/
|
||||
virtual ChanDesc queryChannel (FileHandle, uint chanNo) throw();
|
||||
virtual ChanDesc queryChannel (MediaDesc&, uint chanNo) const;
|
||||
|
||||
virtual ~MediaAccessFacade () {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Descriptor holding the global informations,
|
||||
* needed for further handling this media within Lumiera.
|
||||
*/
|
||||
struct MediaDesc
|
||||
{
|
||||
/** effectively usable duration.
|
||||
* A clip created from this media will have this
|
||||
* maximum duration. We expect to get media stream data
|
||||
* from all channels within this limit.
|
||||
*/
|
||||
Duration length;
|
||||
|
||||
MediaDesc() : length(Duration::NIL) { }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Description of one channel found in a
|
||||
* media file; result of querying the channel.
|
||||
|
|
@ -105,8 +133,15 @@ namespace backend_interface {
|
|||
handle(h)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
} // namespace backend
|
||||
|
||||
|
||||
namespace backend_interface {
|
||||
|
||||
using backend::MediaAccessFacade;
|
||||
using backend::MediaDesc;
|
||||
using backend::ChanDesc;
|
||||
|
||||
} // namespace backend_interface
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ namespace lib {
|
|||
} // namespace test
|
||||
} // namespace lumiera
|
||||
|
||||
namespace backend_interface {
|
||||
namespace backend {
|
||||
class MediaAccessFacade;
|
||||
using lib::Singleton;
|
||||
|
||||
|
|
@ -97,8 +97,8 @@ namespace lib {
|
|||
|
||||
|
||||
template<>
|
||||
class Singleton<backend_interface::MediaAccessFacade>
|
||||
: public MockInjector<backend_interface::MediaAccessFacade>
|
||||
class Singleton<backend::MediaAccessFacade>
|
||||
: public MockInjector<backend::MediaAccessFacade>
|
||||
{ };
|
||||
|
||||
} // namespace lib
|
||||
|
|
|
|||
|
|
@ -22,12 +22,14 @@
|
|||
|
||||
|
||||
#include "pre.hpp"
|
||||
#include "lib/error.hpp"
|
||||
#include "proc/assetmanager.hpp"
|
||||
#include "proc/asset/media.hpp"
|
||||
#include "proc/asset/clip.hpp"
|
||||
#include "proc/asset/unknown.hpp"
|
||||
#include "proc/mobject/session/clip.hpp"
|
||||
#include "proc/mobject/session/mobjectfactory.hpp"
|
||||
#include "backend/mediaaccessfacade.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
#include "lib/util.hpp"
|
||||
#include "include/logging.h"
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
using util::isnil;
|
||||
using lib::time::FSecs;
|
||||
using lib::time::Duration;
|
||||
using backend_interface::MediaDesc;
|
||||
using backend_interface::MediaAccessFacade;
|
||||
|
||||
using boost::format;
|
||||
using boost::regex;
|
||||
|
|
@ -46,6 +50,7 @@ using boost::smatch;
|
|||
using boost::regex_search;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
|
||||
namespace error = lumiera::error;
|
||||
|
||||
namespace asset {
|
||||
|
||||
|
|
@ -134,6 +139,7 @@ namespace asset {
|
|||
* either a asset::Media object or an "Unknown" placeholder will be provided. If
|
||||
* the given Category already contains an "Unkown", we just get the
|
||||
* corresponding smart-ptr. Otherwise a new asset::Unknown is created.
|
||||
* @throw error::Invalid when media file is inaccessible or inappropriate
|
||||
* @return an Media smart ptr linked to the internally registered smart ptr
|
||||
* created as a side effect of calling the concrete Media subclass ctor.
|
||||
*/
|
||||
|
|
@ -157,9 +163,11 @@ namespace asset {
|
|||
else
|
||||
{
|
||||
if (isnil (key.name)) key.name=extractName(file);
|
||||
TODO ("file exists?");
|
||||
TODO ("extract media file properties");
|
||||
Duration length(FSecs(5));
|
||||
|
||||
MediaAccessFacade& maf = MediaAccessFacade::instance();
|
||||
MediaDesc& handle = maf.queryFile(file);
|
||||
Duration length = handle.length;
|
||||
|
||||
TODO ("detecting and wiring multichannel compound media!");
|
||||
pM = new Media (key,file,length);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ TESTING "Proc Layer combined operations Test Suite" ./test-components --group=op
|
|||
|
||||
|
||||
|
||||
TEST "MediaAccessMock_test" MediaAccessMock_test <<END
|
||||
out: accessing "test-1" ...
|
||||
out: Channel-0: nameID=video codecID=ID
|
||||
out: accessing "test-2" ...
|
||||
out: Channel-0: nameID=video codecID=H264
|
||||
out: Channel-1: nameID=audio-L codecID=PCM
|
||||
out: Channel-2: nameID=audio-R codecID=PCM
|
||||
TEST "Mock media access" MediaAccessMock_test <<END
|
||||
out-lit: accessing "test-1" (dur=0:00:25.000)...
|
||||
out-lit: Channel-0: nameID=video codecID=ID
|
||||
out-lit: accessing "test-2" (dur=0:00:25.000)...
|
||||
out-lit: Channel-0: nameID=video codecID=H264
|
||||
out-lit: Channel-1: nameID=audio-L codecID=PCM
|
||||
out-lit: Channel-2: nameID=audio-R codecID=PCM
|
||||
END
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -34,15 +34,21 @@
|
|||
|
||||
|
||||
#include "backend/mediaaccessmock.hpp"
|
||||
#include "proc/mobject/session/testclip.hpp"
|
||||
|
||||
#include "lib/util.hpp"
|
||||
#include "lib/util-foreach.hpp"
|
||||
#include "lib/time/mutation.hpp"
|
||||
#include "lib/symbol.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
using lumiera::error::Invalid;
|
||||
using lib::time::Mutation;
|
||||
using lib::time::Duration;
|
||||
using lib::Literal;
|
||||
using util::for_each;
|
||||
using util::isnil;
|
||||
using std::cout;
|
||||
|
|
@ -51,29 +57,56 @@ using std::vector;
|
|||
using std::map;
|
||||
|
||||
|
||||
namespace backend_interface {
|
||||
namespace backend {
|
||||
namespace test {
|
||||
|
||||
typedef MediaAccessFacade::FileHandle FileHandle;
|
||||
typedef MediaAccessFacade::ChanHandle ChanHandle;
|
||||
|
||||
|
||||
namespace { // implementation details
|
||||
|
||||
typedef vector<ChanDesc> Response;
|
||||
|
||||
struct Response
|
||||
{
|
||||
MediaDesc globalDesc;
|
||||
vector<ChanDesc> channels;
|
||||
|
||||
Response&
|
||||
globalLength (Duration length)
|
||||
{
|
||||
globalDesc.length.accept (Mutation::changeDuration(length));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Response&
|
||||
channel (Literal name, Literal id)
|
||||
{
|
||||
channels.push_back (ChanDesc (name, id, genH()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
static int _i_;
|
||||
ChanHandle genH()
|
||||
{
|
||||
return reinterpret_cast<ChanHandle> (++_i_);
|
||||
}
|
||||
};
|
||||
int Response::_i_(0);
|
||||
const ChanDesc NULLResponse;
|
||||
using mobject::session::test::LENGTH_TestClip;
|
||||
|
||||
|
||||
struct TestCases : map<string,Response>
|
||||
{
|
||||
TestCases ()
|
||||
{
|
||||
// ------------------------------------------------------------------TESTCASES
|
||||
(*this)["test-1"].push_back (ChanDesc ("video","ID", genH()));
|
||||
// ----------------------------------------------------------------------TESTCASES
|
||||
(*this)["test-1"].globalLength(LENGTH_TestClip).channel("video","ID");
|
||||
|
||||
(*this)["test-2"].push_back (ChanDesc ("video","H264", genH()));
|
||||
(*this)["test-2"].push_back (ChanDesc ("audio-L","PCM", genH()));
|
||||
(*this)["test-2"].push_back (ChanDesc ("audio-R","PCM", genH()));
|
||||
// ------------------------------------------------------------------TESTCASES
|
||||
(*this)["test-2"].globalLength(LENGTH_TestClip).channel("video","H264")
|
||||
.channel("audio-L","PCM")
|
||||
.channel("audio-R","PCM");
|
||||
// ----------------------------------------------------------------------TESTCASES
|
||||
}
|
||||
|
||||
bool known (string key)
|
||||
|
|
@ -81,12 +114,6 @@ namespace test {
|
|||
const_iterator i = find (key);
|
||||
return (i != end());
|
||||
}
|
||||
private:
|
||||
int _i_;
|
||||
ChanHandle genH()
|
||||
{
|
||||
return reinterpret_cast<ChanHandle> (++_i_);
|
||||
}
|
||||
};
|
||||
|
||||
// instantiate TestCasses table
|
||||
|
|
@ -95,28 +122,32 @@ namespace test {
|
|||
} // (end) implementation namespace
|
||||
|
||||
|
||||
FileHandle
|
||||
MediaAccessMock::queryFile (const char* name) throw(Invalid)
|
||||
|
||||
MediaDesc&
|
||||
MediaAccessMock::queryFile (string const& name) const
|
||||
{
|
||||
if (isnil (name))
|
||||
throw Invalid ("empty filename passed to MediaAccessFacade.");
|
||||
if (isnil (name))
|
||||
throw Invalid ("empty filename passed to MediaAccessFacade.");
|
||||
|
||||
if (!testCases.known(name))
|
||||
return 0;
|
||||
else
|
||||
return reinterpret_cast<void*> (&testCases[name]);
|
||||
throw Invalid ("unable to use media file \""+name+"\"."
|
||||
"Hint: you're using a test-mock file access, "
|
||||
"which responds only to some magical names.");
|
||||
|
||||
return testCases[name].globalDesc;
|
||||
}
|
||||
|
||||
|
||||
ChanDesc
|
||||
MediaAccessMock::queryChannel (FileHandle h, uint chanNo) throw()
|
||||
MediaAccessMock::queryChannel (MediaDesc& h, uint chanNo) const
|
||||
{
|
||||
const Response* res (reinterpret_cast<Response*> (h));
|
||||
Response const& res (*reinterpret_cast<Response*> (&h));
|
||||
|
||||
if (!res || res->size() <= chanNo)
|
||||
if (res.channels.size() <= chanNo)
|
||||
return NULLResponse;
|
||||
else
|
||||
return (*res)[chanNo];
|
||||
return res.channels[chanNo];
|
||||
}
|
||||
|
||||
|
||||
}} // namespace backend_interface::test
|
||||
}} // namespace backend::test
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
|
||||
|
||||
namespace backend_interface {
|
||||
namespace backend {
|
||||
namespace test {
|
||||
|
||||
/**
|
||||
|
|
@ -39,11 +39,10 @@ namespace test {
|
|||
*/
|
||||
class MediaAccessMock : public MediaAccessFacade
|
||||
{
|
||||
public:
|
||||
FileHandle queryFile (const char* name) throw(lumiera::error::Invalid);
|
||||
ChanDesc queryChannel (FileHandle, uint chanNo) throw();
|
||||
MediaDesc& queryFile (string const& name) const;
|
||||
ChanDesc queryChannel (MediaDesc&, uint chanNo) const;
|
||||
};
|
||||
|
||||
|
||||
}} // namespace backend_interface::test
|
||||
}} // namespace backend::test
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,78 +25,69 @@
|
|||
#include "backend/mediaaccessmock.hpp"
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
//#include "lib/util.hpp"
|
||||
#include "lib/time/diagnostics.hpp"
|
||||
#include "lib/symbol.hpp"
|
||||
|
||||
//#include <boost/format.hpp>
|
||||
#include <iostream>
|
||||
|
||||
//using boost::format;
|
||||
//using util::isnil;
|
||||
using lib::Literal;
|
||||
using std::string;
|
||||
using std::cout;
|
||||
|
||||
|
||||
namespace backend_interface
|
||||
{
|
||||
namespace test
|
||||
namespace backend {
|
||||
namespace test {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* @test inject a Mock object replacing the backend_interface::MediaAccessFacade.
|
||||
* Verify if the Mock object behaves as expected when calling the Facade.
|
||||
*/
|
||||
class MediaAccessMock_test : public Test
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* @test inject a Mock object replacing the backend_interface::MediaAccessFacade.
|
||||
* Verify if the Mock object behaves as expected when calling the Facade.
|
||||
*/
|
||||
class MediaAccessMock_test : public Test
|
||||
{
|
||||
typedef MediaAccessFacade MAF;
|
||||
|
||||
virtual void run(Arg)
|
||||
{
|
||||
MAF::instance.injectSubclass (new MediaAccessMock);
|
||||
|
||||
queryScenario ("test-1");
|
||||
queryScenario ("test-2");
|
||||
|
||||
MAF::instance.injectSubclass (0);
|
||||
}
|
||||
|
||||
|
||||
/** perform the test: query for an (alledged) file
|
||||
* and retrieve the mock answer.
|
||||
*/
|
||||
void queryScenario (string filename)
|
||||
{
|
||||
MAF& maf (MAF::instance());
|
||||
MAF::FileHandle fhandle = maf.queryFile (filename.c_str());
|
||||
if (!fhandle)
|
||||
cout << "File \""<<filename<<"\" not accessible\n";
|
||||
else
|
||||
{
|
||||
cout << "accessing \""<<filename<<"\" ...\n";
|
||||
for (int i=0; true; ++i)
|
||||
{
|
||||
ChanDesc chan = maf.queryChannel (fhandle, i);
|
||||
if (!chan.handle) break;
|
||||
|
||||
cout << " Channel-" << i
|
||||
<< ": nameID=" << chan.chanID
|
||||
<< " codecID=" << chan.codecID
|
||||
<< "\n";
|
||||
} } }
|
||||
|
||||
|
||||
};
|
||||
|
||||
typedef MediaAccessFacade MAF;
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (MediaAccessMock_test, "unit operate");
|
||||
|
||||
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace backend_interface
|
||||
virtual void run(Arg)
|
||||
{
|
||||
MAF::instance.injectSubclass (new MediaAccessMock);
|
||||
|
||||
queryScenario ("test-1");
|
||||
queryScenario ("test-2");
|
||||
|
||||
MAF::instance.injectSubclass (0);
|
||||
}
|
||||
|
||||
|
||||
/** perform the test: query for an (alleged) file
|
||||
* and retrieve the mock answer.
|
||||
*/
|
||||
void queryScenario (string const& filename)
|
||||
{
|
||||
MAF& maf (MAF::instance());
|
||||
MediaDesc& mhandle = maf.queryFile (filename);
|
||||
cout << "accessing \""<<filename<<"\" (dur="<<mhandle.length<<")...\n";
|
||||
for (int i=0; true; ++i)
|
||||
{
|
||||
ChanDesc chan = maf.queryChannel (mhandle, i);
|
||||
if (!chan.handle) break;
|
||||
|
||||
cout << " Channel-" << i
|
||||
<< ": nameID=" << chan.chanID
|
||||
<< " codecID=" << chan.codecID
|
||||
<< "\n";
|
||||
} }
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (MediaAccessMock_test, "unit operate");
|
||||
|
||||
|
||||
|
||||
}} // namespace backend::test
|
||||
|
|
|
|||
|
|
@ -34,9 +34,10 @@ namespace session {
|
|||
namespace test {
|
||||
|
||||
using lib::time::Time;
|
||||
using lib::time::Duration;
|
||||
typedef shared_ptr<asset::Media> PM;
|
||||
typedef backend_interface::MediaAccessFacade MAF;
|
||||
using backend_interface::test::MediaAccessMock;
|
||||
using backend::test::MediaAccessMock;
|
||||
using asset::VIDEO;
|
||||
|
||||
|
||||
|
|
@ -86,7 +87,7 @@ namespace test {
|
|||
|
||||
/* == define some data for verification in unit tests == */
|
||||
|
||||
const Time LENGTH_TestClip(0,25,0,0); //////TODO hard wired as of (1/10). See MediaFactory::operator() in media.cpp
|
||||
const Duration LENGTH_TestClip(Time(0,25,0,0)); //////TODO hard wired as of (1/10). See MediaFactory::operator() in media.cpp / mediaaccessmock.cpp
|
||||
|
||||
|
||||
}}} // namespace mobject::session::test
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ namespace test {
|
|||
|
||||
|
||||
/* == some test data to check == */
|
||||
extern const lib::time::Time LENGTH_TestClip;
|
||||
extern const lib::time::Duration LENGTH_TestClip;
|
||||
|
||||
|
||||
}}} // namespace mobject::session::test
|
||||
|
|
|
|||
Loading…
Reference in a new issue