[libavg-devel] Dynamic Node Creation Enhancements
Ulrich von Zadow
uzadow at libavg.de
Sat Feb 9 23:43:02 CET 2008
Hi,
first of all, apologies for the multiple mails. The misconfiguration
that caused this has been fixed :-).
And second: Very good idea. Good on it's own, and good since it opens
the door for a few more enhancements. I'd probably commit it straight
away if there wasn't any code duplication in the tests...
I spent some time trying to figure out if we can use this as a base to
make the setting of the Node member variables (i.e. most code in the
Node constructors) completely automatic. To do this, Arg would have to
know where to place the value. There are two ways this could could be
implemented:
1. Store C++ member pointers in each Arg. C++ member pointers are very
seldom used, so I'll explain ;-). They basically provide a way to access
a member variable given an object. In the simplest case (single
inheritance), they just store an offset to the member variable. This:
AVGNode::*int pMember
is a pointer to a member of AVGNode, dereferenced by
pNode->*pMember
Anyway, since the type of a member pointer is dependent on the type of
the object and the type of the member variable, this is pretty useless
without some template trickery involving something like
NodeDefinition<NodeT> and Arg<NodeT, ArgT>. To put Args and
NodeDefinitions into containers, there needs to be a non-templated base
class for them as well... since that is going to get convulted and drive
compile times up, I came up with idea 2.
2. Store the offset of the member variable directly, like so:
NodeDefinition(...)
.addArg("enablecrop", "true", (void*)&m_bEnableCrop-(void*)this)
This isn't really nice either (though we could probably hide the void *
casting ugliness in a base class), and we need a this pointer in a
static function, so we'd probably need a temporary bogus object as well.
Still, maybe there are more people who will read and understand that
kind of code than there are people willing to understand template trickery.
On the other hand, both methods would cause the member variable setting
in the node constructors to mostly evaporate down to a single line,
which, I think, would be incredibly cool. Instead of:
CameraNode::CameraNode(const ArgList& Args, Player * pPlayer)
: VideoBase(Args, pPlayer),
m_FrameNum(0)
{
string sDevice = Args.getStringArg ("device");
double FrameRate = Args.getDoubleArg ("framerate");
string sSource = Args.getStringArg ("source");
int Width = Args.getIntArg ("capturewidth");
int Height = Args.getIntArg ("captureheight");
string sPF = Args.getStringArg ("pixelformat");
}
we'd have:
CameraNode::CameraNode(const ArgList& Args, Player * pPlayer)
: VideoBase(Args, pPlayer),
m_FrameNum(0)
{
ArgList.setMembers(this);
}
Just an idea. Tell me what you think.
More comments on the patch inline.
Cheers,
Uli
Nick Hebner wrote:
> Over the weekend, I took a little break from audio to work on some
> enhancements to dynamic node creation. With the included patch, nodes may be
> created through Player::createNode(typeString, argsPythonDictionary). (e.g.
> newNode = Player.createNode("video", {"href":"video.mpg"}) ). To support
> this, I have reworked how arguments are passed to node constructors, and
> created a generic registration mechanism for adding support for different
> types of nodes (also resulting in the ability to dynamically build/change
> the avg DTD). The changes are discussed below.
>
> NodeDefinition
> A NodeDefinition is basically represents all of the information formerly
> found in the avg DTD, that is information about what a type of node is. It
> is composed of a type string, all valid arguments and their default values,
> all valid child nodes, and a function that may be used to build a node of
> this type (Node::buildNode() is a generic template NodeBuilder function that
> can be used in most cases). NodeDefinitions may be extended by subclasses,
> making inheritance of arguments/child nodes simple. Each node type now
> implements a static getNodeDefinition() function which returns the
> information about the type.
>
> NodeFactory
> NodeDefinitions are registered with a NodeFactory, which can then construct
> nodes of the registered type. The NodeFactory handles validation of
> arguments passed to the create function based on the registered
> NodeDefinition of the type being created. Also, all unset args are replaced
> with the default values defined in the NodeDefinition for the type so the
> node constructor may safely request any arg defined in its NodeDefinition.
> Additionally, the NodeFactory can dynamically build a DTD from the complete
> set of NodeDefinitions currently registered with it. The DTD contains a
> single special entity called %anyNode; which contains a | separated list of
> all of the node types registered, and can be used for generic container
> nodes (e.g. avg and div). The dynamic nature of the DTD is very flexible,
> and has been designed with the idea of node plugins in mind, however, it is
> now less visible then before. It would be nice to make the full DTD
> available to the designer (should we add a Player::getDTD() that returns the
> current DTD string in python?).
I think the most important thing here is to have an executable that runs
as part of the make process and generates the dtd. (Granted, we don't
have that now either.)
> Arg/ArgList
> An ArgList is the structure passed to node constructors. It may be build
> from either an xmlNode or a python dictionary object. It provides a simple
> interface for getting arguments in various formats.
>
> The dynamic node tests currently in place have been expanded to use both
> interfaces, and all still pass.
[...]
> Index: /home/nick/workspace/libavg_trunk/src/player/ArgList.h
> ===================================================================
[...]
> +#include "BoostPython.h"
Just something to keep in mind for the future: I'd like to keep the
amount of python-specific code in src/player/ to a minimum to allow for
people who want to use libavg without python.
[...]
> Index: /home/nick/workspace/libavg_trunk/src/test/Test.py
> ===================================================================
> --- /home/nick/workspace/libavg_trunk/src/test/Test.py (revision 2609)
> +++ /home/nick/workspace/libavg_trunk/src/test/Test.py (working copy)
> @@ -913,8 +913,11 @@
> Player.stop))
>
> def testImgDynamics(self):
Why not:
def testImgDynamics(self, useXml):
?
--
Ulrich von Zadow | +49-172-7872715
Jabber: cocacoder at jabber.berlin.ccc.de
Skype: uzadow
More information about the libavg-devel
mailing list