From 38b47b7f93f91e9e8088e35912762b5230156807 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 24 Sep 2007 16:20:41 +0200 Subject: [PATCH] proposal for the MediaAccessFacade (interface to bakend), incl. Mock test --- src/backend/mediaaccessfacade.cpp | 28 +++ src/backend/mediaaccessfacade.hpp | 66 +++++- tests/58proc-operate.tests | 6 + .../common/singletontestmocktest.cpp | 215 +++++++++--------- wiki/renderengine.html | 6 +- 5 files changed, 209 insertions(+), 112 deletions(-) diff --git a/src/backend/mediaaccessfacade.cpp b/src/backend/mediaaccessfacade.cpp index 720c31864..9c86f82dc 100644 --- a/src/backend/mediaaccessfacade.cpp +++ b/src/backend/mediaaccessfacade.cpp @@ -23,6 +23,11 @@ #include "backend/mediaaccessfacade.hpp" +#include "common/util.hpp" + +using util::isnil; +using cinelerra::error::Invalid; + namespace backend_interface { @@ -30,6 +35,29 @@ namespace backend_interface * (actually a cinelerra::test::MockInjector) */ Singleton MediaAccessFacade::instance; + + typedef MediaAccessFacade::FileHandle FileHandle; + typedef MediaAccessFacade::ChanHandle ChanHandle; + + FileHandle + MediaAccessFacade::queryFile (const char* name) throw(Invalid) + { + 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() + { + UNIMPLEMENTED ("delegate to backend: query channel information"); + ChanDesc nix; + return nix; + } + } // namespace backend_interface diff --git a/src/backend/mediaaccessfacade.hpp b/src/backend/mediaaccessfacade.hpp index 24baeb89f..ce994baa8 100644 --- a/src/backend/mediaaccessfacade.hpp +++ b/src/backend/mediaaccessfacade.hpp @@ -26,27 +26,85 @@ #include "common/singleton.hpp" +#include "common/error.hpp" namespace backend_interface { + + struct ChanDesc; - - /** + /****************************************************************** * Interface to the backend layer: * provides functions for querying (opening) a media file, * detecting the channels or streams found within this file etc. * Implemention 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 + * of the invoked function. */ - class MediaAccessFacade + struct MediaAccessFacade { - public: + typedef void* FileHandle; + typedef void* ChanHandle; + static Singleton instance; + /** request for testing the denoted files accessability + * @param name path and filename of the media file. + * @throw invalid when passing empty filename + * @return opaque handle usable for querying channel + * information from this file, NULL if the + * file is not acessible. + */ + virtual FileHandle queryFile (const char* name) throw(cinelerra::error::Invalid); + /** request for information about the n-th channel + * of the file refered by FileHandle. + * @return ChanDesc which may contain \c NULL values if + * the file doesn't contain this much channels. + */ + virtual ChanDesc queryChannel (FileHandle, uint chanNo) throw(); + + virtual ~MediaAccessFacade () {} }; + + /** + * Description of one channel found in a + * media file; result of querying the channel. + */ + struct ChanDesc + { + /** identifier which can be used to create a name + * for the media asset corresponding to this channel. + * May be NULL or empty and need not be unique. + */ + const char* chanID; + + /** identifier characterizing the access method (or codec) + * needed to get at the media data. This should be rather + * a high level description of the media stream type, + * e.g. "H264" -- anyhow, it will be used to find a + * codec asset for this channel. + */ + const char* codecID; + + /** opaque handle, which will be used later to open this + * channel and retrieve some frames from it + */ + MediaAccessFacade::ChanHandle handle; + + ChanDesc (const char* chanName=0, const char* codec=0, + MediaAccessFacade::ChanHandle h=0) + : chanID(chanName), + codecID(codec), + handle(h) + { } + }; + } // namespace backend_interface diff --git a/tests/58proc-operate.tests b/tests/58proc-operate.tests index 3d845e119..07bb240e6 100644 --- a/tests/58proc-operate.tests +++ b/tests/58proc-operate.tests @@ -2,5 +2,11 @@ TESTING "Proc Layer combined operations Test Suite" ./test-components --group=op +TEST "MediaAccessMock_test" MediaAccessMock_test < instance; - - virtual void run(Arg arg) - { - string scenario = isnil(arg)? "default" : arg[1]; - - if (scenario == "default") - injectBoth(); - else + + virtual void run(Arg arg) + { + string scenario = isnil(arg)? "default" : arg[1]; + + if (scenario == "default") + injectBoth(); + else if (scenario == "noMock") noMock(); - else - if (scenario == "onlyMock") - onlyMock(); - else - if (scenario == "firstMock") - firstMock(); - } + else + if (scenario == "onlyMock") + onlyMock(); + else + if (scenario == "firstMock") + firstMock(); + } - - /** @test complete use sequence: first access the Client Object, + + /** @test complete use sequence: first access the Client Object, * then replace it by two different mocks, and finally * restore the original Client Object */ void injectBoth () - { - TestSingletonO* sing = &instance(); - sing->doIt(); - sing->doIt(); - ASSERT (sing->getCnt() == 2); - - instance.injectSubclass (new Mock_1); - sing = &instance(); - sing->doIt(); - sing->doIt(); - sing->doIt(); - sing->doIt(); - sing->doIt(); - ASSERT (sing->getCnt() == 5); - - instance.injectSubclass (new Mock_2); - sing = &instance(); - sing->doIt(); - ASSERT (sing->getCnt() == 1); - - instance.injectSubclass (0); // unshaddowing original instance - sing = &instance(); - ASSERT (sing->getCnt() == 2); - sing->doIt(); - ASSERT (sing->getCnt() == 3); - } + { + TestSingletonO* sing = &instance(); + sing->doIt(); + sing->doIt(); + ASSERT (sing->getCnt() == 2); + + instance.injectSubclass (new Mock_1); + sing = &instance(); + sing->doIt(); + sing->doIt(); + sing->doIt(); + sing->doIt(); + sing->doIt(); + ASSERT (sing->getCnt() == 5); + + instance.injectSubclass (new Mock_2); + sing = &instance(); + sing->doIt(); + ASSERT (sing->getCnt() == 1); + + instance.injectSubclass (0); // unshaddowing original instance + sing = &instance(); + ASSERT (sing->getCnt() == 2); + sing->doIt(); + ASSERT (sing->getCnt() == 3); + } + - /** @test just use Singleton Factory normally without any Mock. */ void noMock () - { - TestSingletonO& sing = instance(); - sing.doIt(); - } + { + TestSingletonO& sing = instance(); + sing.doIt(); + } + - /** @test inject the Mock prior to using the Singleton Factory, * thus the original Client Object shouldn't be created. */ void onlyMock () - { - instance.injectSubclass (new Mock_1); - TestSingletonO& sing = instance(); - sing.doIt(); - } + { + instance.injectSubclass (new Mock_1); + TestSingletonO& sing = instance(); + sing.doIt(); + } + - /** @test inject the Mock prior to using the Singleton Factory, * but then reset the Mock, so following calls should * create the original Client Object. */ void firstMock () - { - instance.injectSubclass (new Mock_1); - TestSingletonO* sing = &instance(); - sing->doIt(); - sing->doIt(); - ASSERT (sing->getCnt() == 2); - - instance.injectSubclass (0); - sing = &instance(); - sing->doIt(); - ASSERT (sing->getCnt() == 1); - } + { + instance.injectSubclass (new Mock_1); + TestSingletonO* sing = &instance(); + sing->doIt(); + sing->doIt(); + ASSERT (sing->getCnt() == 2); + + instance.injectSubclass (0); + sing = &instance(); + sing->doIt(); + ASSERT (sing->getCnt() == 1); + } }; - - - + + + /** Register this test class... */ LAUNCHER (SingletonTestMock_test, "unit common"); - - - + + + } // namespace test } // namespace cinelerra diff --git a/wiki/renderengine.html b/wiki/renderengine.html index f845eb46c..ea3fc49ce 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -1305,10 +1305,10 @@ From experiences with other middle scale projects, I prefer having the test code [img[Example: Interfaces/Namespaces of the ~Session-Subsystems|uml/fig130053.png]] -
+
Opening and accessing media files on disk poses several problems, most of which belong to the domain of cinelerra's data backend. Here, we focus on the questions related to making media data available to the EDL and the render engine. Each media will be represented by an MediaAsset object, which indeed could be a compound object (in case of MultichannelMedia). Building this asset object thus includes getting informations from the real file on disk. For delegating this to the backend, we use the following query interface:
-* {{{openFile(char* name)}}} requests accessing the file and yields some (opaque) handle when successful.
-* {{{getChannel(int)}}} will then be issued in sequence with ascending index numbers, until it returns {{{NULL}}}.
+* {{{queryFile(char* name)}}} requests accessing the file and yields some (opaque) handle when successful.
+* {{{queryChannel(FHandle, int)}}} will then be issued in sequence with ascending index numbers, until it returns {{{NULL}}}.
 * the returned struct (pointer) will provide the following information:
 ** some identifier which can be used to create a name for the corresponding media (channel) asset
 ** some identifier characterizing the access method (codec) needed to get at the media data. This should be rather a high level description of the media stream type, e.g. "H264"