WIP implement the missing create-Clip-from-Asset mechanics
This commit is contained in:
parent
d7e7d3d613
commit
dee1bab28b
17 changed files with 226 additions and 30 deletions
|
|
@ -46,8 +46,9 @@ namespace asset
|
|||
*/
|
||||
Asset::Asset (const Ident& idi)
|
||||
: ident(idi), id(AssetManager::reg (this, idi))
|
||||
{ TRACE (assetmem, "ctor Asset(id=%lu) : adr=%x %s", size_t(id), this, cStr(this->ident) );
|
||||
}
|
||||
{
|
||||
TRACE (assetmem, "ctor Asset(id=%lu) : adr=%x %s", size_t(id), this, cStr(this->ident) );
|
||||
}
|
||||
|
||||
Asset::~Asset ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ namespace asset
|
|||
* May be empty. The head of this list can be considered the primary prerequisite
|
||||
*/
|
||||
vector<shared_ptr<Asset> >
|
||||
getParents () const;
|
||||
getParents () const; ////////////////TODO: better const vector, and return a ref!
|
||||
|
||||
/** All the other assets requiring this asset to be functional.
|
||||
* For example, all the clips depending on a given media file.
|
||||
|
|
|
|||
|
|
@ -26,7 +26,44 @@
|
|||
namespace asset
|
||||
{
|
||||
|
||||
/** */
|
||||
/** Directly object creating specialisation of the
|
||||
* asset::Media interface method: immediately starting
|
||||
* out from this asset::Clip and doing the actual
|
||||
* MObject-creation in case there isn't already
|
||||
* a clip-MO linked with this Clip Asset.
|
||||
*/
|
||||
Media::PClipMO
|
||||
Clip::createClip ()
|
||||
{
|
||||
if (!this.clipMO_)
|
||||
this.clipMO_ = MObject::create(
|
||||
AssetManager::instance()
|
||||
.getAsset (this.getID()));
|
||||
|
||||
return this.clipMO_;
|
||||
}
|
||||
|
||||
|
||||
/** return this wrapped into a shared ptr,
|
||||
* because it's already the desired asset::Clip
|
||||
*/
|
||||
Media::PClip
|
||||
Clip::getClipAsset ()
|
||||
{
|
||||
return PClip (AssetManager::instance()
|
||||
.getAsset (this.getID()));
|
||||
}
|
||||
|
||||
|
||||
/** specialisation delegating the decision to
|
||||
* the media asset referred by this clip
|
||||
*/
|
||||
Media::PMedia
|
||||
Clip::checkCompound ()
|
||||
{
|
||||
return this.source_.checkCompound();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -35,9 +35,21 @@ namespace asset
|
|||
*/
|
||||
class Clip : public Media
|
||||
{
|
||||
protected:
|
||||
/**media source of this clip */
|
||||
const Media* source;
|
||||
/** media source of this clip */
|
||||
const Media& source_;
|
||||
|
||||
/** the corresponding (dependant) clip-MO */
|
||||
PClipMO clipMO_;
|
||||
|
||||
public:
|
||||
virtual PClipMO createClip ();
|
||||
virtual PMedia checkCompound ();
|
||||
|
||||
private:
|
||||
Clip (const Media& mediaref) : source_(mediaref) {};
|
||||
friend class MediaFactory;
|
||||
|
||||
virtual PClip getClipAsset ();
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "proc/asset/clip.hpp"
|
||||
#include "proc/asset/unknown.hpp"
|
||||
#include "proc/mobject/session/clip.hpp"
|
||||
#include "proc/mobject/session/mobjectfactory.hpp"
|
||||
#include "common/util.hpp"
|
||||
#include "nobugcfg.h"
|
||||
|
||||
|
|
@ -62,21 +63,44 @@ namespace asset
|
|||
|
||||
|
||||
|
||||
typedef shared_ptr<mobject::session::Clip> PClip;
|
||||
typedef shared_ptr<asset::ProcPatt> PProcPatt;
|
||||
|
||||
|
||||
PClip
|
||||
Media::PClipMO
|
||||
Media::createClip ()
|
||||
{
|
||||
UNIMPLEMENTED ("create clip from media asset");
|
||||
PClip clip; //TODO:null
|
||||
PClip clipAsset (getClipAsset());
|
||||
PClipMO clipMO = clipAsset->createClip();
|
||||
|
||||
ENSURE (clip);
|
||||
ENSURE (clipMO->isValid());
|
||||
return clip;
|
||||
}
|
||||
|
||||
PProcPatt
|
||||
|
||||
/** @internal used to either create an asset::Clip denoting the whole media,
|
||||
* or to get the right reference to some already existing asset::Clip,
|
||||
* especially when this media is part of a compound (multichannel) media.
|
||||
*/
|
||||
Media::PClip
|
||||
Media::getClipAsset ()
|
||||
{
|
||||
if (PMedia parent = this.checkCompound())
|
||||
return parent->getClipAsset();
|
||||
else
|
||||
return Media::create(*this);
|
||||
}
|
||||
|
||||
|
||||
Media::PMedia
|
||||
Media::checkCompound()
|
||||
{
|
||||
PAsset parents = this.getParents();
|
||||
PMedia parent(0);
|
||||
if ( !isnil (parents)) // primary parent is a media asset?
|
||||
parent = dynamic_pointer_cast (parents[0]);
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
||||
Media::PProcPatt
|
||||
Media::howtoProc ()
|
||||
{
|
||||
UNIMPLEMENTED ("calculate and return processing pattern for media asset");
|
||||
|
|
@ -120,6 +144,7 @@ namespace asset
|
|||
{
|
||||
if (isnil (key.name)) key.name=extractName(file);
|
||||
TODO ("file exists?");
|
||||
TODO ("detecting and wiring multichannel compound media!");
|
||||
pM = new Media (key,file);
|
||||
}
|
||||
ASSERT (pM);
|
||||
|
|
@ -170,6 +195,32 @@ namespace asset
|
|||
if (!file) file = "";
|
||||
return operator() (key, string(file));
|
||||
}
|
||||
|
||||
|
||||
/** Factory method for creating a Clip asset based
|
||||
* on the given Media asset. This asset::Clip can be used
|
||||
* to create clip in the EDL covering the whole length of
|
||||
* this media.
|
||||
* @throw Invalid if the given media asset is not top-level,
|
||||
* but rather part or a multichannel (compound) media
|
||||
*/
|
||||
shared_ptr<asset::Clip>&
|
||||
MediaFactory::operator() (const asset::Media& mediaref) throw(cinelerra::error::Invalid)
|
||||
{
|
||||
if (mediaref.checkCompound())
|
||||
throw cinelerra::error::Invalid (CINELERRA_ERROR_PART_OF_COMPOUND,
|
||||
format("Attempt to create a asset::Clip from the media %s, "
|
||||
"which is not toplevel but rather part or a compound "
|
||||
"(multichannel) media. Found parent Media %s.")
|
||||
% mediaref
|
||||
% string(mediaref.checkCompound()));
|
||||
asset::Clip* pC = new asset::Clip (mediaref);
|
||||
return AssetManager::instance().getAsset (pC->getID());
|
||||
}
|
||||
|
||||
CINELERRA_ERROR_DEFINE (PART_OF_COMPOUND, "part of compound used as toplevel element");
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace asset
|
||||
|
|
|
|||
|
|
@ -37,10 +37,10 @@
|
|||
|
||||
#include "proc/asset.hpp"
|
||||
#include "common/factory.hpp"
|
||||
#include "proc/mobject/mobject.hpp"
|
||||
|
||||
|
||||
|
||||
namespace mobject { namespace session { class Clip; }}
|
||||
|
||||
namespace asset
|
||||
{
|
||||
|
|
@ -69,6 +69,12 @@ namespace asset
|
|||
string filename_;
|
||||
|
||||
public:
|
||||
typedef shared_ptr<Media> PMedia;
|
||||
typedef shared_ptr<const asset::Clip> PClip;
|
||||
typedef shared_ptr<asset::ProcPatt> PProcPatt;
|
||||
typedef mobject::Placement<mobject::session::Clip> PClipMO;
|
||||
|
||||
|
||||
static MediaFactory create;
|
||||
const string& getFilename () const { return filename_; }
|
||||
|
||||
|
|
@ -77,12 +83,36 @@ namespace asset
|
|||
return static_cast<const ID<Media>& > (Asset::getID());
|
||||
}
|
||||
|
||||
shared_ptr<mobject::session::Clip> createClip ();
|
||||
shared_ptr<asset::ProcPatt> howtoProc ();
|
||||
/** Service Access Point for creating a Clip entity usable within
|
||||
* the EDL/Session from a given Media or Clip Asset. As a sideeffect,
|
||||
* a corresponding asset::Clip is created as well if necessary.
|
||||
* It is OK to use and throw away the returned Clip-MO, because
|
||||
* it can be regenerated from the corresponding asset::Clip
|
||||
* @return a Placement smart ptr owning the new Clip MObject
|
||||
*/
|
||||
PClipMO createClip ();
|
||||
|
||||
/** Service Access Point for getting a processing template
|
||||
* describing how to build the render nodes network
|
||||
* necessary for this Media or Clip. This includes
|
||||
* Codecs and postprocessing (stretching, deinterlacing...)
|
||||
*/
|
||||
PProcPatt howtoProc ();
|
||||
|
||||
protected:
|
||||
Media (const Asset::Ident& idi, const string& file) : Asset(idi), filename_(file) {}
|
||||
friend class MediaFactory;
|
||||
|
||||
/** get or create the correct asset::Clip
|
||||
* corresponding to this media */
|
||||
virtual PClip getClipAsset ();
|
||||
|
||||
/** predicate to decide if this asset::Media
|
||||
* is part of a compound (multichannel) media.
|
||||
* @return pointer to parent, or \code null
|
||||
*/
|
||||
virtual PMedia checkCompound ();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -110,9 +140,14 @@ namespace asset
|
|||
PType operator() (Asset::Ident& key, const char* file); ///< convienience overload using C-String
|
||||
PType operator() (const char* file, const Category& cat);
|
||||
PType operator() (const char* file, asset::Kind);
|
||||
|
||||
shared_ptr<asset::Clip>&
|
||||
operator() (const asset::Media& mediaref) throw(cinelerra::error::Invalid);
|
||||
|
||||
};
|
||||
|
||||
CINELERRA_ERROR_DECLARE (PART_OF_COMPOUND);
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace asset
|
|||
{
|
||||
|
||||
/**
|
||||
* AssetManager error responses, cause by querying
|
||||
* AssetManager error responses, caused by querying
|
||||
* invalid Asset IDs from the internal DB.
|
||||
*/
|
||||
class IDErr : public cinelerra::error::Invalid
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ namespace asset
|
|||
throw(cinelerra::error::Invalid);
|
||||
|
||||
/** deleter function used by the Asset smart pointers to delet Asset objects */
|
||||
static void destroy (Asset* m) { delete m; }
|
||||
static void destroy (Asset* aa) { delete aa; }
|
||||
|
||||
friend Asset::Asset (const Asset::Ident& idi);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,10 @@
|
|||
namespace mobject
|
||||
{
|
||||
|
||||
/** */
|
||||
/** Storage for the (single, static) MObject factory object.
|
||||
*/
|
||||
session::MObjectFactory MObject::create;
|
||||
|
||||
|
||||
|
||||
} // namespace mobject
|
||||
|
|
|
|||
|
|
@ -69,6 +69,9 @@ namespace mobject
|
|||
public:
|
||||
static session::MObjectFactory create;
|
||||
|
||||
/** MObject self-test (usable for asserting) */
|
||||
virtual bool isValid() =0;
|
||||
|
||||
virtual PAsset getMedia () =0; ///< @todo solve the reference/Interface problem concerning Placements, then push down
|
||||
virtual Time& getLength() =0; ///< @todo how to deal with the time/length field??
|
||||
|
||||
|
|
|
|||
|
|
@ -90,9 +90,11 @@ namespace mobject
|
|||
virtual MO *
|
||||
operator-> () const
|
||||
{
|
||||
ENSURE (this.get());
|
||||
return shared_ptr::operator-> ();
|
||||
}
|
||||
|
||||
|
||||
/** interface for defining the kind of placement
|
||||
* to employ, and for controling any additional
|
||||
* constraints and properties.
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ namespace mobject
|
|||
shared_ptr<Placement> placement_;
|
||||
|
||||
public:
|
||||
|
||||
/* some dummy implementations used to make the code compile... */
|
||||
|
||||
virtual shared_ptr<Placement>& getPlacement () { return placement_; }
|
||||
virtual Time& getLength() { return length; }
|
||||
virtual PAsset getMedia ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,7 +28,26 @@ namespace mobject
|
|||
namespace session
|
||||
{
|
||||
|
||||
/** */
|
||||
/** new clip-MO linked with the given asset::Clip.
|
||||
* Initially, this clip will cover the whole source media length.
|
||||
*/
|
||||
Clip::Clip (PClipAsset& mediaDef)
|
||||
: start_(0),
|
||||
mediaDef_(mediaDef)
|
||||
{
|
||||
this.setupLength();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Clip::setupLength()
|
||||
{
|
||||
UNIMPLEMENTED ("calculate the length of a clip and set length field");
|
||||
// will use mediaDef to query media parameters....
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,15 @@ namespace mobject
|
|||
Time start;
|
||||
|
||||
//TODO: where to put the duration ???
|
||||
|
||||
PClipAsset mediaDef_;
|
||||
|
||||
Clip (PClipAsset& mediaDef);
|
||||
friend class MObjectFactory;
|
||||
|
||||
|
||||
virtual void setupLength();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ namespace mobject
|
|||
* asset.
|
||||
*/
|
||||
Placement<Clip>
|
||||
MObjectFactory::operator() (shared_ptr<asset::Clip>& mediaDef)
|
||||
MObjectFactory::operator() (PClipAsset& mediaDef)
|
||||
{
|
||||
//TODO sholdin't we rather store a ref to the underlying media assset??
|
||||
return Placement<Clip> (new Clip (mediaDef));
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ namespace asset
|
|||
{
|
||||
class Clip;
|
||||
class Effect;
|
||||
|
||||
}
|
||||
|
||||
namespace mobject
|
||||
|
|
@ -41,13 +42,14 @@ namespace mobject
|
|||
class Clip;
|
||||
class Effect;
|
||||
|
||||
typedef shared_ptr<const asset::Clip> PClipAsset;
|
||||
|
||||
class MObjectFactory
|
||||
{
|
||||
public:
|
||||
typedef Placement PType;
|
||||
|
||||
PType<Clip> operator() (const asset::Clip);
|
||||
PType<Clip> operator() (PClipAsset&);
|
||||
PType<Effect> operator() (const asset::Effect);
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1397,16 +1397,19 @@ This Design strives to achieve a StrongSeparation between the low-level Structur
|
|||
[[Admin]]
|
||||
<<fullscreen>></pre>
|
||||
</div>
|
||||
<div title="ManagementAssetRelation" modifier="Ichthyostega" modified="200709021538" created="200708100337" tags="impl" changecount="3">
|
||||
<pre>Problem is: when removing an Asset, all corresponding MObjects need to disappear. This means, besides the obvious ~Ref-Link (MObject refering to an asset) we need backlinks or a sort of registry. And still worse: we need to remove the affetcted MObject from the object network in the EDL and rebuild the Fixture...
|
||||
<div title="ManagementAssetRelation" modifier="Ichthyostega" modified="200710191600" created="200708100337" tags="impl" changecount="6">
|
||||
<pre>Problem is: when removing an Asset, all corresponding MObjects need to disappear. This means, besides the obvious ~Ref-Link (MObject referring to an asset) we need backlinks or a sort of registry. And still worse: we need to remove the affected MObject from the object network in the EDL and rebuild the Fixture...
|
||||
|
||||
&rarr; for a general design discussion see [[Relation of Clip and Asset|RelationClipAsset]]
|
||||
|
||||
As a //first shot// Ichthyo considers the following approach:
|
||||
* all references between MObjects and Assets are implemented as refcounting boost::shared_ptr
|
||||
* all references between MObjects and Assets are implemented as __refcounting__ boost::shared_ptr
|
||||
* the opposite direction is also a __strong references__, effectively keeping the clip-MO alive even if it is no longer in use in the session (note this is a cyclic dependency that needs to be actively broken on deletion). This design decision is based on logical considerations (&rarr; see "deletions, Model-2" [[here|RelationClipAsset]]). The back-link is needed only for clean deletion of Assets and for GUI search functions.
|
||||
* MObjects and Assets implement an {{{unlink()}}} function releasing the internal links to other entities.
|
||||
* Instead of a delete, we call this unlink() function and let the shared_ptr handle the actual deletion.
|
||||
* we don't use a registry, rather we model the real dependencies by individual dependency links. So a MediaAsset gets links to all Clips created from this Asset and by traversing this tree, we can handle the deletion
|
||||
* after the deletion, the Fixture needs to be rebuilt.
|
||||
* but any render processes still can have pointers to the Asset to be removed, and the shared_ptr will ensure, that the refered objects stay alive as long as needed.
|
||||
* but any render processes still can have pointers to the Asset to be removed, and the shared_ptr will ensure, that the referred objects stay alive as long as needed.
|
||||
|
||||
{{red{to be considered in more detail later}}}
|
||||
</pre>
|
||||
|
|
@ -2085,7 +2088,7 @@ DAMAGE.
|
|||
|
||||
The fact of being placed in the [[Session|SessionOverview]]/[[EDL]]is constitutive for all sorts of [[MObject]]s, without Placement they make no sense. Thus &mdash; technically &mdash; Placements act as ''smart pointers''. Of course, there are several kinds of Placements and they are templated on the type of MObject they are refering to. Placements can be //aggregated// to increasingly constrain the resulting "location" of the refered ~MObject. See &rarr; [[handling of Placements|PlacementHandling]] for more details</pre>
|
||||
</div>
|
||||
<div title="PlacementHandling" modifier="Ichthyostega" modified="200710181534" created="200710100124" tags="design" changecount="10">
|
||||
<div title="PlacementHandling" modifier="Ichthyostega" modified="200710191414" created="200710100124" tags="design impl" changecount="11">
|
||||
<pre>[[Placement]]s are at the very core of all [[editing operations|EditingOperations]], because they act as handles (smart pointers) to access the [[media objects|MObject]] to be manipulated. Moreover, Placements are the actual content of the EDL(s) and Fixture and thus are small objects with //value semantics//. Many editing tasks include finding some Placement in the EDL or directly take a ref to some Placement. By acting on the Placement object, we can in some cases change parameters of the way the media object is placed (e.g. adjust an offset), while by dereferencing the Placement object, we access the "real" media object (e.g. for trimming its length). Placements are ''templated'' on the type of the actual ~MObject they refer to, thus defining the interface/methods usable on this object.
|
||||
|
||||
Actually, the way each Placement locates its subject is implemented by one or several small LocatingPin objects, where subclasses of LocatingPin implement the various differend methods of placing and resolving the final location. Notably, we can give a ~FixedLocation or we can atach to another ~MObject to get a ~RelativeLocation, etc.
|
||||
|
|
@ -2395,6 +2398,26 @@ config.macros.rssFeedUpdate = {
|
|||
//}}}
|
||||
</pre>
|
||||
</div>
|
||||
<div title="RelationClipAsset" modifier="Ichthyostega" modified="200710191558" created="200710191541" tags="design decision" changecount="3">
|
||||
<pre>What is the Role of the asset::Clip and how exactly are Assets and (Clip)-MObjects related?
|
||||
|
||||
First of all: ~MObjects are the dynamic/editing/manipulation view, while Assets are the static/bookkeeping/searching/information view of the same entities. Thus, the asset::Clip contains the general configuration, the ref to the media and descriptive properties, while all parameters being "manipulated" belong to the session::Clip (MObject). Besides that, the practical purpose of asset::Clip is that you can save and remember some selection as a Clip (Asset), maybe even attach some informations or markup to it, and later be able to (re)create a editable representation in the Session (the GUI could implement this by allowing to drag from the asset::Clip GUI representation to the timeline window)
|
||||
|
||||
!!dependencies
|
||||
The session::Clip (frequently called "clip-MO", i.e. the MObject) //depends on the Asset.// It can't exist without the Asset, because the Asset is needed for rendering. The other direction is different: the asset::Clip knows that there is a dependant clip-MO, there could be //at most one// such clip-MO depending on the Asset, but the Asset can exist without the clip-MO (it gives the possibility to re-create the clip-MO).
|
||||
|
||||
!!deletions
|
||||
When the Asset or the corresponding asset::Media is deleted, the dependant clip-MO has to disappear. And the opposite direction?
|
||||
* Model-1: asset::Clip has a weak ref to the clip-MO. Consequently, the clip-MO can go out of scope and disappear, so the asset::Clip has to maintain the information of the clip's dimensions (source position and length) somewhere. Because of MultichannelMedia, this is not so simple as it may look at first sight.
|
||||
* Model-2: asset::Clip holds a smart ptr to the clip-MO, thus effectively keeping it alive. __obviously the better choice__
|
||||
In either case, we have to solve the ''problem of clip asset proliferation''
|
||||
|
||||
!!multiplicity and const-ness
|
||||
The link between ~MObject and Asset should be {{{const}}} in both directions (to enforce the separation of concerns). So the Asset can't //edit// the clip and the clip can't change the media parameters.
|
||||
|
||||
The relation logical relation, but it is not strictly 1:1 because typical media are [[multichannel|MultichannelMedia]]. Even if the media is compound, there is //only one asset::Clip//, because in the logical view we have only one "clip-thing". On the other hand, in the Session/EDL, we have a compound clip ~MObject comprised of several elementary clip objects, each of which will refer to its own sub-media (channel) within the compound media (and don't forget, this structure can be tree-like)
|
||||
{{red{open question:}}} do the clip-MO's of the individual channels refer directly to asset::Media? does this mean the relation is different from the top level, where we have a relation to a asset::Clip??</pre>
|
||||
</div>
|
||||
<div title="RenderEngine" modifier="Ichthyostega" modified="200708050630" created="200706190056" tags="overview" changecount="40">
|
||||
<pre>The Render Engine is the part of the application doing the actual video calculations. Its operations are guided by the Objects and Parameters edited by the user in [[the EDL|EDL]] and it retrieves the raw audio and video data from the [[Data backend|backend.html]]. Because the inner workings of the Render Engine are closely related to the structures used in the EDL, this design covers [[this aspect|MObjects]] as well.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue