adapt Media-Access (+Mock) to include an overall Duration

This commit is contained in:
Fischlurch 2011-05-18 01:37:33 +02:00
parent 46c9811184
commit a207a9f003
10 changed files with 195 additions and 134 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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