Merge branch 'master' of git://git.lumiera.org/LUMIERA into gui

This commit is contained in:
Joel Holdsworth 2008-10-17 23:40:40 +01:00
commit 60beab4933
80 changed files with 4723 additions and 444 deletions

View file

@ -62,7 +62,6 @@ include $(top_srcdir)/icons/Makefile.am
include $(top_srcdir)/tests/common/Makefile.am
include $(top_srcdir)/tests/components/Makefile.am
include $(top_srcdir)/tests/Makefile.am
include $(top_srcdir)/tests/plugin/Makefile.am
#EXTRA_DIST += admin debian doc depcomp README.BUILD LICENSE \
# cinelerra-cvs-current.spec

View file

@ -1,5 +1,5 @@
AC_INIT(lumiera, 0.1pre)
AC_CONFIG_SRCDIR(src/lib/plugin.c)
AC_CONFIG_SRCDIR(src/lib/luid.c)
AC_CONFIG_AUX_DIR(scripts)
AM_INIT_AUTOMAKE
AC_PREREQ(2.59)

View file

@ -18,7 +18,7 @@
liblumibackend_a_srcdir = $(top_srcdir)/src/backend
noinst_LIBRARIES += liblumibackend.a
liblumibackend_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror
liblumibackend_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wextra -Wall -Werror
liblumibackend_a_SOURCES = \
$(liblumibackend_a_srcdir)/mediaaccessfacade.cpp \
@ -27,10 +27,13 @@ liblumibackend_a_SOURCES = \
$(liblumibackend_a_srcdir)/filehandle.c \
$(liblumibackend_a_srcdir)/filedescriptor.c \
$(liblumibackend_a_srcdir)/filehandlecache.c \
$(liblumibackend_a_srcdir)/interface.c \
$(liblumibackend_a_srcdir)/interfaceregistry.c \
$(liblumibackend_a_srcdir)/config.c \
$(liblumibackend_a_srcdir)/config_typed.c \
$(liblumibackend_a_srcdir)/config_wordlist.c \
$(liblumibackend_a_srcdir)/configentry.c \
$(liblumibackend_a_srcdir)/configitem.c \
$(liblumibackend_a_srcdir)/configitem.c \
$(liblumibackend_a_srcdir)/config_lookup.c
@ -41,8 +44,11 @@ noinst_HEADERS += \
$(liblumibackend_a_srcdir)/filehandle.h \
$(liblumibackend_a_srcdir)/filedescriptor.h \
$(liblumibackend_a_srcdir)/filehandlecache.h \
$(liblumibackend_a_srcdir)/interface.h \
$(liblumibackend_a_srcdir)/interfaceregistry.h \
$(liblumibackend_a_srcdir)/interfacedescriptor.h \
$(liblumibackend_a_srcdir)/config.h \
$(liblumibackend_a_srcdir)/configentry.h \
$(liblumibackend_a_srcdir)/configitem.h \
$(liblumibackend_a_srcdir)/configitem.h \
$(liblumibackend_a_srcdir)/config_lookup.h

View file

@ -111,7 +111,7 @@ lumiera_config_init (const char* path)
lumiera_configitem_init (&lumiera_global_config->files);
lumiera_configitem_init (&lumiera_global_config->TODO_unknown);
lumiera_rwlock_init (&lumiera_global_config->lock, "config rwlock", &NOBUG_FLAG (config));
lumiera_mutex_init (&lumiera_global_config->lock, "config mutex", &NOBUG_FLAG (config));
lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "config.path = %s", path));
@ -130,7 +130,7 @@ lumiera_config_destroy ()
TRACE (config);
if (lumiera_global_config)
{
lumiera_rwlock_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (config));
lumiera_mutex_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (config));
lumiera_configitem_destroy (&lumiera_global_config->defaults, &lumiera_global_config->keys);
lumiera_configitem_destroy (&lumiera_global_config->files, &lumiera_global_config->keys);
lumiera_configitem_destroy (&lumiera_global_config->TODO_unknown, &lumiera_global_config->keys);
@ -146,6 +146,7 @@ lumiera_config_destroy ()
int
lumiera_config_load (const char* file)
{
(void) file;
TRACE (config);
UNIMPLEMENTED();
return -1;
@ -164,6 +165,7 @@ lumiera_config_save ()
int
lumiera_config_purge (const char* filename)
{
(void) filename;
TRACE (config);
UNIMPLEMENTED();
@ -290,7 +292,7 @@ lumiera_config_setdefault (const char* line)
LumieraConfigitem item = NULL;
LUMIERA_WRLOCK_SECTION (config, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config, &lumiera_global_config->lock)
{
const char* key = line;
while (*key && isspace (*key))
@ -342,6 +344,7 @@ lumiera_config_dump (FILE* out)
int
lumiera_config_reset (const char* key)
{
(void) key;
TRACE (config);
UNIMPLEMENTED();
return -1;
@ -351,6 +354,9 @@ lumiera_config_reset (const char* key)
int
lumiera_config_info (const char* key, const char** filename, unsigned* line)
{
(void) key;
(void) filename;
(void) line;
TRACE (config);
UNIMPLEMENTED();
return -1;

View file

@ -24,7 +24,7 @@
//TODO: Support library includes//
#include "lib/error.h"
#include "lib/rwlock.h"
#include "lib/mutex.h"
//TODO: Forward declarations//
struct lumiera_config_struct;
@ -74,14 +74,7 @@ struct lumiera_config_struct
lumiera_configitem files; /* all loaded files */
lumiera_configitem TODO_unknown; /* all values which are not part of a file and not default TODO: this will be removed when file support is finished */
/*
all access is protected with rwlock's.
We use rwlocks here since concurrent reads are likely common.
So far this is a global config lock, if this is a problem we might granularize it by locking on a file level.
config access is not planned to be transactional yet, if this is a problem we need to expose the rwlock to a config_acquire/config_release function pair
*/
lumiera_rwlock lock;
lumiera_mutex lock;
};
typedef struct lumiera_config_struct lumiera_config;
@ -96,6 +89,7 @@ typedef lumiera_config* LumieraConfig;
LUMIERA_CONFIG_TYPE(number, signed long long) \
LUMIERA_CONFIG_TYPE(real, long double) \
LUMIERA_CONFIG_TYPE(string, const char*) \
LUMIERA_CONFIG_TYPE(wordlist, const char*) \
LUMIERA_CONFIG_TYPE(word, const char*) \
LUMIERA_CONFIG_TYPE(bool, int)
@ -197,7 +191,7 @@ lumiera_config_set (const char* key, const char* delim_value);
* Installs a default value for a config key.
* Any key might have an associated default value which is used when
* no other configuration is available, this can be set once.
* Any subsequent call will be a no-op. This function writelocks the config system.
* Any subsequent call will be a no-op. This function locks the config system.
* @param line line with key, delimiter and value to store as default value
* @return NULL in case of an error, else a pointer to the default configitem
*/
@ -223,7 +217,57 @@ lumiera_config_setdefault (const char* line);
LUMIERA_CONFIG_TYPES
#undef LUMIERA_CONFIG_TYPE
/**
* Wordlists
* Wordlists are lists of single words delimited by any of " \t,;".
* They can be used to store groups of keys and other kinds of simple references into the config
* system. Here are some functions to manipulate single word entries in a wordlist.
*/
/**
* Get nth word of a wordlist.
* @param key key under which this wordlist is stored
* @param nth index of the word to get, starting with 0
* @return pointer to a tempbuf holding the nth word or NULL in case of error
*/
const char*
lumiera_config_wordlist_get_nth (const char* key, unsigned nth);
/**
* Find the index of a word in a wordlist.
* @param key key under which this wordlist is stored
* @param value word to find
* @return index of the first occurence of the word or -1 in case of failure
*/
int
lumiera_config_wordlist_find (const char* key, const char* value);
/**
* Universal word replacement function.
* Replaces a word with up to two new words. This can be used to delete a word (no replacements),
* insert a new word before an existing word (giving the new word as subst1 and the old word as subst2)
* insert a new word after an existing word (giving the old word as subst1 and the new word as subst2)
* or simply give 2 new words.
* @param key key under which this wordlist is stored
* @param value word to be replaced
* @param subst1 first replacement word
* @param subst2 second replacement word
* @return internal representation of the wordlist in a tmpbuf or NULL in case of an error
*/
const char*
lumiera_config_wordlist_replace (const char* key, const char* value, const char* subst1, const char* subst2);
/**
* Add a word to the end of a wordlist if it doesnt exist already
* @param key key under which this wordlist is stored
* @param value new word to add
* @return internal representation of the wordlist in a tmpbuf or NULL in case of an error
*/
const char*
lumiera_config_wordlist_add (const char* key, const char* value);
// * {{{ lumiera_config_TYPE_set (const char* key, TYPE*value, const char* fmt) }}}
// Highlevel interface for different types, fmt is a printf format specifier for the desired format, when NULL, defaults apply.

View file

@ -41,6 +41,7 @@ extern LumieraConfig lumiera_global_config;
const char*
lumiera_config_link_get (const char* key, const char** value)
{
(void) key; (void) value;
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
@ -49,6 +50,7 @@ lumiera_config_link_get (const char* key, const char** value)
LumieraConfigitem
lumiera_config_link_set (const char* key, const char** value)
{
(void) key; (void) value;
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
@ -66,7 +68,7 @@ lumiera_config_number_get (const char* key, long long* value)
const char* raw_value = NULL;
LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
if (lumiera_config_get (key, &raw_value))
{
@ -94,7 +96,7 @@ lumiera_config_number_set (const char* key, long long* value)
LumieraConfigitem item = NULL;
LUMIERA_WRLOCK_SECTION (config_typed, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
const char* fmt = "= %lld"; TODO ("use the config system (config.format*...) to deduce the desired format for this key");
item = lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, fmt, *value));
@ -111,6 +113,7 @@ lumiera_config_number_set (const char* key, long long* value)
const char*
lumiera_config_real_get (const char* key, long double* value)
{
(void) key; (void) value;
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
@ -119,6 +122,7 @@ lumiera_config_real_get (const char* key, long double* value)
LumieraConfigitem
lumiera_config_real_set (const char* key, long double* value)
{
(void) key; (void) value;
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
@ -195,7 +199,7 @@ lumiera_config_string_get (const char* key, const char** value)
const char* raw_value = *value = NULL;
LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
if (lumiera_config_get (key, &raw_value))
{
@ -218,7 +222,7 @@ lumiera_config_string_set (const char* key, const char** value)
LumieraConfigitem item = NULL;
LUMIERA_WRLOCK_SECTION (config_typed, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
const char* fmt = "= %s"; TODO ("use the config system (config.format*...) to deduce the desired format for this key");
item = lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, fmt, *value));
@ -228,6 +232,53 @@ lumiera_config_string_set (const char* key, const char** value)
}
/**
* Wordlist
* words delimited by any of " \t,;"
*/
const char*
lumiera_config_wordlist_get (const char* key, const char** value)
{
TRACE (config_typed, "KEY %s", key);
const char* raw_value = *value = NULL;
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
if (lumiera_config_get (key, &raw_value))
{
if (raw_value)
{
*value = raw_value;
}
else
LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
TODO ("remove the ERROR_SET because config_get sets it already? also in all other getters in this file");
}
}
return *value;
}
LumieraConfigitem
lumiera_config_wordlist_set (const char* key, const char** value)
{
TRACE (config_typed);
LumieraConfigitem item = NULL;
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
const char* fmt = "= %s"; TODO ("use the config system (config.format*...) to deduce the desired format for this key");
item = lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, fmt, *value));
}
return item;
}
/**
* Word
@ -262,7 +313,7 @@ lumiera_config_word_get (const char* key, const char** value)
const char* raw_value = *value = NULL;
LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
if (lumiera_config_get (key, &raw_value))
{
@ -285,7 +336,7 @@ lumiera_config_word_set (const char* key, const char** value)
LumieraConfigitem item = NULL;
LUMIERA_WRLOCK_SECTION (config_typed, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
const char* fmt = "= %s"; TODO ("use the config system (config.format*...) to deduce the desired format for this key");
item = lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, fmt, scan_word (*value)));
@ -302,6 +353,7 @@ lumiera_config_word_set (const char* key, const char** value)
const char*
lumiera_config_bool_get (const char* key, int* value)
{
(void) key; (void) value;
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
@ -311,6 +363,7 @@ lumiera_config_bool_get (const char* key, int* value)
LumieraConfigitem
lumiera_config_bool_set (const char* key, int* value)
{
(void) key; (void) value;
TRACE (config_typed);
UNIMPLEMENTED();
return 0;

View file

@ -0,0 +1,217 @@
/*
config_wordlist.c - Lumiera wordlist access functions
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//TODO: Support library includes//
#include "lib/error.h"
#include "lib/safeclib.h"
//TODO: Lumiera header includes//
#include "backend/config.h"
//TODO: internal/static forward declarations//
extern LumieraConfig lumiera_global_config;
//TODO: System includes//
/**
* return nth word of a wordlist
*/
const char*
lumiera_config_wordlist_get_nth (const char* key, unsigned nth)
{
const char* value;
size_t len;
if (!lumiera_config_wordlist_get (key, &value))
return NULL;
for (;;)
{
value += strspn (value, " \t,;");
len = strcspn (value, " \t,;");
if (!nth && *value)
break;
--nth;
value += len;
if (!*value)
return NULL;
}
return lumiera_tmpbuf_strndup (value, len);
}
int
lumiera_config_wordlist_find (const char* key, const char* value)
{
const char* itr;
size_t vlen = strlen (value);
size_t len;
if (!lumiera_config_wordlist_get (key, &itr))
return -1;
for (int idx = 0; *itr; itr += len, ++idx)
{
itr += strspn (itr, " \t,;");
len = strcspn (itr, " \t,;");
if (len == vlen && !strncmp (itr, value, vlen))
return idx;
}
return -1;
}
const char*
lumiera_config_wordlist_replace (const char* key, const char* value, const char* subst1, const char* subst2)
{
const char* wordlist;
const char* str = NULL;
size_t vlen = strlen (value);
size_t len;
if (!value)
return NULL;
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
if (lumiera_config_get (key, &wordlist))
{
const char* start = wordlist + strspn (wordlist, " \t,;");
for (const char* itr = start; *itr; itr += len)
{
const char* left_end = itr;
itr += strspn (itr, " \t,;");
len = strcspn (itr, " \t,;");
if (len == vlen && !strncmp (itr, value, vlen))
{
TODO ("figure delimiter from original string out");
const char* delim = " ";
/* step over the word */
itr += len;
itr += strspn (itr, " \t,;");
/* getting the delimiters right for the corner cases looks ugly, want to refactor it? just do it */
str = lumiera_tmpbuf_snprintf (SIZE_MAX,
"%.*s%.*s%s%s%s%s%s%s",
start - wordlist, wordlist,
left_end - start, start,
(left_end - start && subst1 && *subst1) ? delim : "",
(subst1 && *subst1) ? subst1 : "",
((left_end - start || (subst1 && *subst1)) && subst2 && *subst2) ? delim : "",
(subst2 && *subst2) ? subst2 : "",
((left_end - start || (subst1 && *subst1) || (subst2 && *subst2)) && *itr) ? delim : "",
itr
);
if (!lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, "=%s", str)))
str = NULL;
break;
}
}
}
}
return str;
}
const char*
lumiera_config_wordlist_add (const char* key, const char* value)
{
const char* wordlist = NULL;
if (value && *value)
{
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
if (lumiera_config_get (key, &wordlist))
{
size_t vlen = strlen (value);
size_t len;
for (const char* itr = wordlist; *itr; itr += len)
{
itr += strspn (itr, " \t,;");
len = strcspn (itr, " \t,;");
if (len == vlen && !strncmp (itr, value, vlen))
goto end;
}
TODO ("figure delimiter from original string out");
const char* delim = " ";
wordlist = lumiera_tmpbuf_snprintf (SIZE_MAX, "%s%s%s",
wordlist,
wordlist[strspn (wordlist, " \t,;")]?delim:"",
value);
if (!lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, "=%s", wordlist)))
wordlist = NULL;
}
end:;
}
}
return wordlist;
}
#if 0
const char*
lumiera_config_wordlist_remove_nth (const char* key, unsigned nth)
{
}
LumieraConfigitem
lumiera_config_wordlist_append (const char* key, const char** value, unsigned nth)
{
}
LumieraConfigitem
lumiera_config_wordlist_preprend (const char* key, const char** value, unsigned nth)
{
}
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -241,8 +241,8 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line)
itr += self->key_size;
/*we need a key with a length greather than zero and
* either the end of the line
* or a whitespace after the key */
* either end of line
* or whitespace after key */
if ( self->key_size && ( !*itr || (*itr && isspace(*itr)) ))
{

View file

@ -42,7 +42,7 @@ NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all);
This registry stores all acquired filedescriptors for lookup, they will be freed when not referenced anymore.
*/
static PSplay registry = NULL;
static lumiera_mutex registry_mutex = {PTHREAD_MUTEX_INITIALIZER};
static lumiera_mutex registry_mutex = {PTHREAD_MUTEX_INITIALIZER NOBUG_RESOURCE_HANDLE_COMMA_INITIALIZER};
static int
@ -96,7 +96,9 @@ lumiera_filedescriptor_registry_init (void)
if (!registry)
LUMIERA_DIE (NO_MEMORY);
RESOURCE_HANDLE_INIT (registry_mutex.rh);
TODO ("LumieraMutex lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag);");
// RESOURCE_HANDLE_INIT (registry_mutex.rh);
RESOURCE_ANNOUNCE (filedescriptor, "mutex", "filedescriptor registry", &registry, registry_mutex.rh);
}
@ -108,6 +110,8 @@ lumiera_filedescriptor_registry_destroy (void)
RESOURCE_FORGET (filedescriptor, registry_mutex.rh);
TODO ("LumieraMutex lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag);");
if (registry)
psplay_destroy (registry);
registry = NULL;

293
src/backend/interface.c Normal file
View file

@ -0,0 +1,293 @@
/*
interface.c - Lumiera interface api
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/mutex.h"
#include "lib/safeclib.h"
#include "backend/interface.h"
#include "backend/interfaceregistry.h"
#include <nobug.h>
/**
* @file
* From a programmers perspective interfaces only need to be opened when needed and closed
* when finished with them. There is no difference if the interface is internally provided
* by the core or provided by an external plugin.
* Interfaces can be opened multiple times and cross reference each other.
*/
static LumieraInterfacenode
lumiera_interface_open_interfacenode (LumieraInterfacenode self);
static void
lumiera_interfacenode_close (LumieraInterfacenode self);
LumieraInterface
lumiera_interface_open (const char* interface, unsigned version, size_t minminorversion, const char* name)
{
LumieraInterfacenode self = NULL;
TRACE (interface, "%s", name);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
self = lumiera_interfaceregistry_interfacenode_find (interface, version, name);
if (!self)
{
UNIMPLEMENTED ("query plugindb and load plugin if exists");
}
if (self)
{
if (minminorversion > self->interface->size)
{
UNIMPLEMENTED ("set error");
self = NULL;
}
else
{
self = lumiera_interface_open_interfacenode (self);
}
}
}
return self->interface;
}
static void
push_dependency (LumieraInterfacenode parent, LumieraInterfacenode child)
{
/* push a dependency on the dependency array, allcoate or resize it on demand */
TRACE (interface, "%s %s", parent->interface->name, child->interface->name);
/* no dependencies recorded yet, alloc a first block for 4 pointers */
if (!parent->deps_size)
parent->deps = lumiera_calloc (parent->deps_size = 4, sizeof (LumieraInterfacenode));
size_t sz = parent->deps_size;
LumieraInterfacenode* itr = parent->deps;
while (*itr)
{
--sz;
++itr;
if (sz == 1)
{
/* block to small, realloc it with twice its size, we keep the block NULL terminated */
sz = parent->deps_size + 1;
parent->deps_size *= 2;
parent->deps = lumiera_realloc (parent->deps, parent->deps_size * sizeof (LumieraInterface));
itr = parent->deps + sz - 2;
memset (itr, 0, sz * sizeof (LumieraInterface));
}
}
/* found free element, store self in dependencies */
*itr = child;
}
static void
depwalk (LumieraInterfacenode self, LumieraInterfacenode* stack)
{
/* increment refcount for all non-cyclic dependencies recursively */
if (self->deps)
{
TRACE (interface, "%s %d", self->interface->name, self->refcnt);
for (LumieraInterfacenode* dep = self->deps; *dep; ++dep)
{
TRACE (interface, "loop %s", (*dep)->interface->name);
int cycle = 0;
for (LumieraInterfacenode itr = *stack; itr; itr = itr->lnk)
{
if (itr == *dep)
{
TRACE (interface, "CYCLE");
cycle = 1;
break;
}
}
if (!cycle)
{
++(*dep)->refcnt;
(*dep)->lnk = *stack;
*stack = *dep;
depwalk (*dep, stack);
*stack = (*dep)->lnk;
(*dep)->lnk = NULL;
}
}
}
}
static LumieraInterfacenode
lumiera_interface_open_interfacenode (LumieraInterfacenode self)
{
static unsigned collect_dependencies = 0;
static LumieraInterfacenode stack = NULL;
/*
Ok, this got little more complicated than it should be,
but finally it handles any kind of cross dependencies between interfaces gracefully
*/
if (self)
{
TRACE (interface, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:"");
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
/* discover cycles, cycles don't refcount! */
int cycle = 0;
for (LumieraInterfacenode itr = stack; itr; itr = itr->lnk)
{
if (itr == self)
{
TRACE (interface, "CYCLE");
cycle = 1;
break;
}
}
/* 'stack' is ensured to be !NULL here because only a parent call can switch collect_dependencies on */
if (collect_dependencies)
push_dependency (stack, self);
if (!cycle)
{
++self->refcnt;
self->lnk = stack;
stack = self;
int collect_dependencies_bak = collect_dependencies;
if (self->refcnt == 1)
{
/* first opening, run acquire, recursive opening shall record its dependencies here */
if (self->interface->acquire)
{
TRACE (interface, "Acquire %s", self->interface->name);
collect_dependencies = self->deps?0:1;
self->interface = self->interface->acquire (self->interface);
}
}
else
{
/* opening again recurse dependencies */
collect_dependencies = 0;
depwalk (self, &stack);
}
collect_dependencies = collect_dependencies_bak;
stack = self->lnk;
self->lnk = NULL;
}
}
}
return self;
}
void
lumiera_interface_close (LumieraInterface self)
{
TRACE (interface);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
lumiera_interfacenode_close ((LumieraInterfacenode)psplay_find (lumiera_interfaceregistry, self, 100));
}
}
/* internal function, does no locking! */
static void
lumiera_interfacenode_close (LumieraInterfacenode self)
{
static LumieraInterfacenode stack = NULL;
if (!self)
return;
TRACE (interface, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:"");
REQUIRE (self->refcnt);
int cycle = 0;
for (LumieraInterfacenode itr = stack; itr; itr = itr->lnk)
{
if (itr == self)
{
TRACE (interface, "CYCLE");
cycle = 1;
break;
}
}
if (!cycle)
{
self->lnk = stack;
stack = self;
if (self->refcnt == 1)
{
if (self->interface->release)
{
TRACE (interface, "Release %s", self->interface->name);
self->interface->release (self->interface);
}
}
else
{
if (self->deps)
{
TRACE (interface, "Recurse %s %d", self->interface->name, self->refcnt);
for (LumieraInterfacenode* dep = self->deps; *dep; ++dep)
lumiera_interfacenode_close (*dep);
}
}
stack = self->lnk;
self->lnk = NULL;
--self->refcnt;
}
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

408
src/backend/interface.h Normal file
View file

@ -0,0 +1,408 @@
/*
interface.h - Lumiera interface macros and structures
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LUMIERA_INTERFACE_H
#define LUMIERA_INTERFACE_H
#include "lib/luid.h"
#include "lib/ppmpl.h"
#include "lib/psplay.h"
/* TODO better doxygen formating */
/**
* @file
* Lumiera interface macros and structures.
*
* Instead just simple function/library bindings, Lumiera uses a system of
* versioned interfaces. This interfaces are C-binding compatible and thus
* can be used by any language which can bind to C. This interfaces are versioned
* to provide exceptional forward and backward compatibility for both, source and
* binary deployment of modules. This interfaces play a central role on the Lumiera
* architecture, other facilities, like serializing sessions and distributed computing
* will use them extensively.
*
* Overview
*
* Interfaces are used for two purposes in Lumiera:
* 1. The core uses them internally and exports its functionality though them.
* 2. Plugins (effects,...) extend Lumiera by providing interfaces
*
* We define some macros here which ease the declaration and definition of interfaces.
*
* Declaration of an interface happens in a header and has the form:
* LUMIERA_INTERFACE_DECLARE(name, version,
* LUMIERA_INTERFACE_SLOT(ret, name, params),
* ...
* )
* Any code which want to use this interface must then include its declaration.
*
* Basic definition of an interface is done by mapping functions to slots or giving
* inline definitions for slot functions:
* LUMIERA_INTERFACE_INSTANCE(iname, version, name, descriptor, acquire, release,
* LUMIERA_INTERFACE_MAP (slot, luid, function),
* LUMIERA_INTERFACE_INLINE (slot, luid, ret, params, {body}),
* ...
* )
*
* There are 2 ways to define collections of interfaces:
* LUMIERA_EXPORT(queryfunc,
* LUMIERA_INTERFACE_DEFINE(...),
* ...
* )
* to export interfaces from the core.
*
* LUMIERA_PLUGIN(descriptor, acquire, release, luid,
* LUMIERA_INTERFACE_DEFINE(...),
* ...
* )
* is used to export interfaces from a plugin.
*
* Naming and Versioning
* Interfaces have unique names and a major and minor version. The name and the major version
* is used to construct a C identifier for the interface, the minor version is implicit defined
* by the number of functions a interface. Interface instances are not versioned by the
* interface system, versioning these shall be defined somewhere else.
*
* Slot names are normal C identifiers, how these shall be versioned has to be defined somewhere
* else and is not subject of the interface system. Each function can has its own unique uuid.
*/
/*
Interface declaration macros
*/
/**
* Construct a type identifier for an interface
* @param name name of the interface
* @param version major version of this interface
*/
#define LUMIERA_INTERFACE_INAME(name, version) name##_##version
/**
* Construct a definition identifier for an interface
* @param iname name of the interface
* @param version major version of the interface
* @param dname name for the instance
*/
#define LUMIERA_INTERFACE_DNAME(iname, version, dname) PPMPL_CAT (LUMIERA_INTERFACE_INAME(iname, version), _##dname)
/**
* Return a reference (pointer) to an interface implementation
* @param iname name of the interface
* @param version major version of the interface
* @param dname name for the instance
*/
#define LUMIERA_INTERFACE_REF(iname, version, dname) \
(LumieraInterface)&LUMIERA_INTERFACE_DNAME(iname, version, dname)
/**
* Construct the type of the interface
* @param name name of the interface
* @param version major version of this interface
*/
#define LUMIERA_INTERFACE_TYPE(name, version) struct LUMIERA_INTERFACE_INAME(name, version)
/**
* Construct a cast to the target interface type
* Used to cast a generic LumieraInterface to the real type
* @param name name of the interface
* @param version major version of this interface
*/
#define LUMIERA_INTERFACE_CAST(name, version) (LUMIERA_INTERFACE_TYPE(name, version)*)
/**
* Declare an interface.
* @param name name of the interface
* @param version major version of this interface declaration. 0 denotes a experimental interface,
* otherwise this shall be counting from 1 upwards for each new (incompatible) change of an interface.
* The older interface declarations may still be maintained in parallel (backwards compatibility!).
* @param ... Slot declarations for the functions provided by this interface @see LUMIERA_INTERFACE_SLOT
* The number of Slots in an interface defines its 'minor' version.
* New slots must be added at the end. The prototype and order of existing slots must not be changed.
* Slots may be renamed, for example a slot 'foo' can be renamed to 'foo_old' when a new 'foo' slot is
* added. Binary modules will then still use the 'foo_old' slot which was the 'foo' slot at their
* compile time while compiling modules from source will use the new 'foo' slot. This may be
* intentionally used to break compilation and force the update of modules to a new api.
*/
#define LUMIERA_INTERFACE_DECLARE(name, version, ...) \
LUMIERA_INTERFACE_TYPE(name, version) \
{ \
lumiera_interface interface_header_; \
PPMPL_FOREACH(_, __VA_ARGS__) \
}
/**
* Declare function slot inside an interface.
* @param ret return type of the function
* @param name name of this slot
* @param params parentized list of parameters for the function
*/
#define PPMPL_FOREACH_LUMIERA_INTERFACE_SLOT(ret, name, params) ret (*name) params; lumiera_uid name##_uid;
/*
Interface definition macros
*/
/**
* Define a interface instance.
* @param iname name of the interface to instance
* @param version major version of the interface to instance
* @param name name of the instance
* @param descriptor pointer to an interface instance which provides a description of this interface, might be NULL
* @param acquire a function which is called whenever this interface is opened for using, might be NULL
* @param release a function which is called whenever this interface is closed after use, might be NULL
* @param ... map functions to interface slots @see LUMIERA_INTERFACE_MAP
*/
#define LUMIERA_INTERFACE_INSTANCE(iname, version, name, descriptor, acquire, release, ...) \
PPMPL_FOREACH(_P1_, __VA_ARGS__) \
LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, version, name) = \
{ \
{ \
#iname, \
version, \
#name, \
sizeof (LUMIERA_INTERFACE_TYPE(iname, version)), \
descriptor, \
acquire, \
release \
}, \
PPMPL_FOREACH(_P2_, __VA_ARGS__) \
}
/**
* Map a function to a interface slot
* @param slot name of the slot to be mapped
* @param luid unique identifier for this function, use the magic word LUIDGEN here and run the
* lumiera uuid generator tool (to be written) over the source file to generate luid's automatically
* @param function name of the function to be mapped on slot
*
* @note C++ requires that all mappings are in the same order than defined in the interface declaration,
* this would be good style for C too anyways
*/
#define PPMPL_FOREACH_P1_LUMIERA_INTERFACE_MAP(slot, luid, function)
#ifdef __cplusplus
#define PPMPL_FOREACH_P2_LUMIERA_INTERFACE_MAP(slot, luid, function) \
function, LUMIERA_UID_INITIALIZER (luid),
#else
#define PPMPL_FOREACH_P2_LUMIERA_INTERFACE_MAP(slot, luid, function) \
.slot = function, .slot##_uid = LUMIERA_UID_INITIALIZER (luid),
#endif
/**
* Map a inline defined function to a interface slot
* @param slot name of the slot to be mapped
* @param luid unique identifier for this function, use the magic word LUIDGEN here and run the
* lumiera uuid generator tool (to be written) over the source file to generate luid's automatically
* @param ret return type of the inline function
* @param params parentized list of parameters given to the function
* @param ... braced function body
*
* @note C++ requires that all mappings are in the same order than defined in the interface declaration,
* this would be good style for C too anyways
*/
#define PPMPL_FOREACH_P1_LUMIERA_INTERFACE_INLINE(slot, luid, ret, params, ...) \
static ret \
LUMIERA_INTERFACE_INLINE_NAME(slot) params \
__VA_ARGS__
#ifdef __cplusplus
#define PPMPL_FOREACH_P2_LUMIERA_INTERFACE_INLINE(slot, luid, ret, params, ...) \
LUMIERA_INTERFACE_INLINE_NAME(slot), LUMIERA_UID_INITIALIZER (luid),
#else
#define PPMPL_FOREACH_P2_LUMIERA_INTERFACE_INLINE(slot, luid, ret, params, ...) \
.slot = LUMIERA_INTERFACE_INLINE_NAME(slot), .slot##_uid = LUMIERA_UID_INITIALIZER (luid),
#endif
#define LUMIERA_INTERFACE_INLINE_NAME(slot) PPMPL_CAT(lumiera_##slot##_l, __LINE__)
#define PPMPL_FOREACH_L1_P1_LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, acquire, release, ...) \
LUMIERA_INTERFACE_INSTANCE (iname, version, \
name, \
descriptor, \
acquire, \
release, \
__VA_ARGS__ \
);
#define PPMPL_FOREACH_L1_P2_LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, acquire, release, ...) \
&LUMIERA_INTERFACE_DNAME(iname, version, name).interface_header_,
/**
* Generate interface container suitable for enumerating interfaces.
* This takes a list of interface definitions, instantiates them and places pointers to them
* into a zero terminated array which address is returned by the a created function.
* For interfaces generated by he core, the user is responsible to register these at the
* plugindb dynamically
* @param queryfunc name of the function to be created.
* @param ... list of LUMIERA_INTERFACE_DEFINE() for all interfaces this plugin provides.
*/
#define LUMIERA_EXPORT(queryfunc, ...) \
PPMPL_FOREACH_L1(_P1_, __VA_ARGS__) \
static LumieraInterface* \
queryfunc (void) \
{ \
static LumieraInterface interfaces[] = \
{ \
PPMPL_FOREACH_L1(_P2_, __VA_ARGS__) \
NULL \
}; \
return interfaces; \
}
/**
* Generate interface container suitable for a lumiera plugin.
* This takes a list of interface definitions and places pointers to them into a zero terminated array. Further
* it instances a local 'plugin interface' which will be picked up by the plugin loader to query the array of
* provided interfaces.
* @param descriptor pointer to an interface instance which provides a description of this plugin, might be NULL
* @param acquire a function which is called whenever the plugin interface is opened for using, might be NULL
* @param release a function which is called whenever this plugin interface is closed after use, might be NULL
* @param luid unique identifier for the this plugin interfaces query, use the magic word LUIDGEN here and run the
* lumiera uuid generator tool (to be written) over the source file to generate luid's automatically
* @param ... list of LUMIERA_INTERFACE_DEFINE() for all interfaces this plugin provides.
*/
#define LUMIERA_PLUGIN(descriptor, acquire, release, luid, ...) \
LUMIERA_EXPORT(plugin_interfaces, __VA_ARGS__) \
LUMIERA_INTERFACE_DEFINE (lumieraorg_plugin, 0, \
lumieraorg_plugin_0, \
NULL, \
NULL, \
NULL, \
LUMIERA_INTERFACE_MAP (plugin_interfaces, plugin_interfaces, luid) \
)
/**
* create a handle for a interface (WIP)
*/
#define LUMIERA_INTERFACE_HANDLE(interface, version) \
LUMIERA_INTERFACE_TYPE(interface, version)*
#define LUMIERA_INTERFACE_OPEN(interface, version, minminor, name) \
LUMIERA_INTERFACE_CAST(interface, version) lumiera_interface_open (#interface, version, minminor, #name)
typedef struct lumiera_interfaceslot_struct lumiera_interfaceslot;
typedef lumiera_interfaceslot* LumieraInterfaceslot;
typedef struct lumiera_interface_struct lumiera_interface;
typedef lumiera_interface* LumieraInterface;
/**
* This is just a placeholder for an entry in a interface table.
* It consists of one here generic, later correctly prototyped function pointer and
* a unique identifier which is associated with this function.
*/
struct lumiera_interfaceslot_struct
{
void (*func)(void);
lumiera_uid uid;
};
/**
* Header for an interface, just the absolute necessary metadata.
*/
struct lumiera_interface_struct
{
/** name of the interface (type) */
const char* interface;
/** major version, 0 means experimental */
unsigned version;
/** name of this instance */
const char* name;
/** size of the whole interface structure (minor version) */
size_t size;
/** metadata descriptor, itself a interface (or NULL) */
LumieraInterface descriptor;
/**
* Must be called before this interface is used.
* might be nested.
* @param self pointer to the interface to be acquired
* @return pointer to the interface or NULL on error
*/
LumieraInterface (*acquire)(LumieraInterface self);
/**
* called when finished using this interface
* must match the acquire calls
* @param self pointer to the interface to be released
*/
void (*release)(LumieraInterface self);
#ifndef __cplusplus
/** placeholder array for the following function slots, C++ doesn't support flexible arrays */
lumiera_interfaceslot functions[];
#endif
};
/*
API to handle interfaces
*/
/**
* Open an interface by version and name.
* Looks up the requested interface, possibly loading it from a plugin.
* @param interface name of the interface definition
* @param version major version of the interface definition
* @param minminorversion required minor version (structure size)
* @param name name of the interface implementation
* @return the queried interface handle on success, else NULL
*/
LumieraInterface
lumiera_interface_open (const char* interface, unsigned version, size_t minminorversion, const char* name);
/**
* Close an interface after use.
* @param self interface to be closed
* consider 'self' to be invalidated after this call
*/
void
lumiera_interface_close (LumieraInterface iface);
#endif /* LUMIERA_INTERFACE_H */
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -0,0 +1,48 @@
/*
interfacedescriptor.h - Metadata interface for Lumiera interfaces
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LUMIERA_INTERFACEDESCRIPTOR_H
#define LUMIERA_INTERFACEDESCRIPTOR_H
#include "backend/interface.h"
/**
* WIP: interface descriptor, needs some generic metadata interface
*/
LUMIERA_INTERFACE_DECLARE (lumieraorg_interfacedescriptor, 0,
/* The following slots are some human-readable descriptions of certain properties */
LUMIERA_INTERFACE_SLOT (const char*, name, (LumieraInterface)),
LUMIERA_INTERFACE_SLOT (const char*, version, (LumieraInterface)),
LUMIERA_INTERFACE_SLOT (const char*, author, (LumieraInterface)),
LUMIERA_INTERFACE_SLOT (const char*, copyright, (LumieraInterface)),
LUMIERA_INTERFACE_SLOT (const char*, license, (LumieraInterface))
/* TODO add more things here, dependencies, provisions etc */
);
#endif /* LUMIERA_INTERFACEDESCRIPTORS_H */
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -0,0 +1,255 @@
/*
interfaceregistry.c - Lumiera interface registry
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/mutex.h"
#include "lib/error.h"
#include "lib/psplay.h"
#include "lib/safeclib.h"
#include <nobug.h>
#include "backend/interfaceregistry.h"
/**
* @file
* Interface instances are published and activated by registering them
* into a global registry, which is defined here. This instances are identified
* by their name and major version.
*/
NOBUG_DEFINE_FLAG_PARENT (interface_all, backend);
NOBUG_DEFINE_FLAG_PARENT (interfaceregistry, interface_all);
NOBUG_DEFINE_FLAG_PARENT (interface, interface_all);
PSplay lumiera_interfaceregistry;
lumiera_mutex lumiera_interface_mutex;
static int
cmp_fn (const void* keya, const void* keyb);
static const void*
key_fn (const PSplaynode node);
static LumieraInterfacenode
lumiera_interfacenode_new (LumieraInterface iface)
{
LumieraInterfacenode self = lumiera_malloc (sizeof (*self));
psplaynode_init (&self->node);
self->interface = iface;
self->refcnt = 0;
self->lnk = NULL;
self->deps_size = 0;
self->deps = NULL;
return self;
}
static void
lumiera_interfacenode_delete (LumieraInterfacenode self)
{
if (self)
{
REQUIRE (self->refcnt == 0);
lumiera_free (self->deps);
lumiera_free (self);
}
}
/**
* Initialize the interface registry
*/
void
lumiera_interfaceregistry_init (void)
{
NOBUG_INIT_FLAG (interface_all);
NOBUG_INIT_FLAG (interfaceregistry);
NOBUG_INIT_FLAG (interface);
TRACE (interfaceregistry);
REQUIRE (!lumiera_interfaceregistry);
lumiera_interfaceregistry = psplay_new (cmp_fn, key_fn, NULL);
if (!lumiera_interfaceregistry)
LUMIERA_DIE (ERRNO);
lumiera_recmutex_init (&lumiera_interface_mutex, "interfaceregistry", &NOBUG_FLAG(interfaceregistry));
}
void
lumiera_interfaceregistry_destroy (void)
{
TRACE (interfaceregistry);
REQUIRE (!psplay_nelements (lumiera_interfaceregistry));
lumiera_mutex_destroy (&lumiera_interface_mutex, &NOBUG_FLAG(interfaceregistry));
if (lumiera_interfaceregistry)
psplay_destroy (lumiera_interfaceregistry);
lumiera_interfaceregistry = NULL;
}
void
lumiera_interfaceregistry_register_interface (LumieraInterface self)
{
TRACE (interfaceregistry);
REQUIRE (self);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
TRACE (interfaceregistry, "interface %s, version %d, instance %s", self->interface, self->version, self->name);
psplay_insert (lumiera_interfaceregistry, &lumiera_interfacenode_new (self)->node, 100);
}
}
void
lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self)
{
TRACE (interfaceregistry);
REQUIRE (self);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
while (*self)
{
TRACE (interfaceregistry, "interface %s, version %d, instance %s", (*self)->interface, (*self)->version, (*self)->name);
psplay_insert (lumiera_interfaceregistry, &lumiera_interfacenode_new (*self)->node, 100);
++self;
}
}
}
void
lumiera_interfaceregistry_remove_interface (LumieraInterface self)
{
TRACE (interfaceregistry);
REQUIRE (self);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
LumieraInterfacenode node = (LumieraInterfacenode) psplay_find (lumiera_interfaceregistry, self, 0);
REQUIRE (node->refcnt == 0, "but is %d", node->refcnt);
lumiera_interfacenode_delete ((LumieraInterfacenode)psplay_remove (lumiera_interfaceregistry, &node->node));
}
}
void
lumiera_interfaceregistry_bulkremove_interfaces (LumieraInterface* self)
{
TRACE (interfaceregistry);
REQUIRE (self);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
while (*self)
{
TRACE (interfaceregistry, "interface %s, version %d, instance %s", (*self)->interface, (*self)->version, (*self)->name);
LumieraInterfacenode node = (LumieraInterfacenode) psplay_find (lumiera_interfaceregistry, *self, 0);
REQUIRE (node->refcnt == 0, "but is %d", node->refcnt);
lumiera_interfacenode_delete ((LumieraInterfacenode) psplay_remove (lumiera_interfaceregistry, &node->node));
++self;
}
}
}
LumieraInterfacenode
lumiera_interfaceregistry_interfacenode_find (const char* interface, unsigned version, const char* name)
{
TRACE (interfaceregistry);
struct lumiera_interface_struct cmp;
cmp.interface = interface;
cmp.version = version;
cmp.name = name;
LumieraInterfacenode ret = NULL;
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
ret = (LumieraInterfacenode)psplay_find (lumiera_interfaceregistry, &cmp, 100);
}
return ret;
}
LumieraInterface
lumiera_interfaceregistry_interface_find (const char* interface, unsigned version, const char* name)
{
return lumiera_interfaceregistry_interfacenode_find (interface, version, name)->interface;
}
static int
cmp_fn (const void* keya, const void* keyb)
{
const LumieraInterface a = (const LumieraInterface)keya;
const LumieraInterface b = (const LumieraInterface)keyb;
int r = strcmp (a->interface, b->interface);
if (r<0)
return -1;
else if (r>0)
return 1;
if (a->version < b->version)
return -1;
else if (a->version > b->version)
return 1;
r = strcmp (a->name, b->name);
if (r<0)
return -1;
else if (r>0)
return 1;
return 0;
}
static const void*
key_fn (const PSplaynode node)
{
return ((LumieraInterfacenode)node)->interface;
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -0,0 +1,114 @@
/*
interfaceregistry.h - Lumiera interface registry
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LUMIERA_INTERFACEREGISTRY_H
#define LUMIERA_INTERFACEREGISTRY_H
#include "lib/mutex.h"
#include "lib/psplay.h"
#include "backend/interface.h"
#include <nobug.h>
/**
* @file
* Interface instances are published and activated by registering them
* into a gloabl registry, which is defined here. This instances are identified
* by their name and major version.
*/
NOBUG_DECLARE_FLAG (interface_all);
NOBUG_DECLARE_FLAG (interfaceregistry);
NOBUG_DECLARE_FLAG (interface);
extern PSplay lumiera_interfaceregistry;
extern lumiera_mutex lumiera_interface_mutex;
/**
* Interface management node.
* All active interfaces managed through this node which contains the dynamic data for
* dependency tracking and reference counting.
*/
typedef struct lumiera_interfacenode_struct lumiera_interfacenode;
typedef lumiera_interfacenode* LumieraInterfacenode;
struct lumiera_interfacenode_struct
{
/** all known interfaces are registered in a tree */
psplaynode node;
/** the interface itself */
LumieraInterface interface;
/** reference counters and link used for internal reference management */
unsigned refcnt;
/** temporary used to stack interfaces when recursively opening/closing them */
LumieraInterfacenode lnk;
/** allocated size of the following deps table */
size_t deps_size;
/** NULL terminated table of all dependenncies (interfaces opened on initialization) */
LumieraInterfacenode* deps;
};
extern lumiera_mutex lumiera_interface_mutex;
/**
* Initialize the interface registry
*/
void
lumiera_interfaceregistry_init (void);
void
lumiera_interfaceregistry_destroy (void);
void
lumiera_interfaceregistry_register_interface (LumieraInterface self);
void
lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self);
void
lumiera_interfaceregistry_remove_interface (LumieraInterface self);
void
lumiera_interfaceregistry_bulkremove_interfaces (LumieraInterface* self);
LumieraInterfacenode
lumiera_interfaceregistry_interfacenode_find (const char* interface, unsigned version, const char* name);
LumieraInterface
lumiera_interfaceregistry_interface_find (const char* interface, unsigned version, const char* name);
#endif /* LUMIERA_INTERFACEREGISTRY_H */
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -27,8 +27,9 @@
#include <time.h>
#include <limits.h>
#include "plugin.h"
#include "safeclib.h"
#include "lib/safeclib.h"
#include "backend/plugin.h"
/**
* @file

View file

@ -63,7 +63,7 @@ namespace lumiera
* std::tr1::shared_ptr, but forwarding type relationships and
* ordering operators to the pointee objects.
* @param TAR the visible pointee type
* @param the shared-ptr type used as implementation
* @param BASE the shared-ptr type used as implementation
* @note if the BASE smart-ptr type used as implementation
* implies another pointer type than the one used on
* the interface (=type TAR), then every access to the

37
src/common/streamtype.cpp Normal file
View file

@ -0,0 +1,37 @@
/*
StreamType - classification of media stream types
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
#include "common/streamtype.hpp"
namespace lumiera
{
/** @internal defined here non-inline place the vtable in this object file.*/
StreamType::ImplFacade::ImplFacade (Symbol libID)
: libraryID(libID)
{ }
} // namespace lumiera

183
src/common/streamtype.hpp Normal file
View file

@ -0,0 +1,183 @@
/*
STREAMTYPE.hpp - classification of media stream types
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file streamtype.hpp
** Framework for classification of media streams.
** Besides the actual implementation type of a media stream, the Proc-Layer
** needs a more general way for accessing, comparing and manipulating media streams
** based on type information.
**
** @see control::STypeManager
**
*/
#ifndef LUMIERA_STREAMTYPE_HPP
#define LUMIERA_STREAMTYPE_HPP
#include "common/query.hpp"
#include <boost/noncopyable.hpp>
namespace lumiera {
/**
*
*/
struct StreamType : boost::noncopyable
{
enum MediaKind
{
VIDEO,
IMMAGE,
AUDIO,
MIDI
};
enum Usage
{
RAW,
SOURCE,
TARGET,
INTERMEDIARY
};
struct Prototype;
class ImplFacade;
class ImplConstraint;
Prototype const& prototype;
ImplFacade * implType; /////////////TODO: really by ptr???
Usage intentionTag;
};
/**
*
*/
struct StreamType::Prototype
{
Symbol id;
MediaKind kind;
bool subsumes (Prototype const& other) const;
bool canRender (Prototype const& other) const;
};
/**
* A (more or less) concrete implementation type, wired up
* as a facade providing the basic set of operations.
*/
class StreamType::ImplFacade
{
public:
Symbol libraryID;
class TypeTag ;
/** placeholder definition for the contents of a data buffer */
struct DataBuffer { };
virtual bool operator== (ImplFacade const& other) const =0;
virtual bool operator== (StreamType const& other) const =0;
virtual bool canConvert (ImplFacade const& other) const =0;
virtual bool canConvert (StreamType const& other) const =0;
virtual DataBuffer* createFrame () const =0;
virtual MediaKind getKind() const =0;
virtual ~ImplFacade() {};
protected:
ImplFacade (Symbol libID) ;
};
/**
* Special case of an implementation type being only partialiy specified
* Besides requiring some aspect of the implementation type, there is the
* promise to fill in defaults to build a complete implementation type
* if necessary.
*/
class StreamType::ImplConstraint
: public StreamType::ImplFacade
{
public:
virtual bool canConvert (ImplFacade const& other) const =0;
virtual bool canConvert (StreamType const& other) const =0;
virtual bool subsumes (ImplFacade const& other) const =0;
/** modify the other impl type such as to comply with this constraint */
virtual void makeCompliant (ImplFacade & other) const =0;
/** create a default impl type in accordance to this constraint
* and use it to create a new framebuffer */
virtual DataBuffer* createFrame () const =0;
/** similarily create a impl type which complies to this constraint
* as well as to the additional constraints (e.g. frame size).
* Create a new framebuffer of the resutling type */
virtual DataBuffer* createFrame (ImplConstraint const& furtherConstraints) const =0;
//TODO: do we need functions to represent and describe this constraint?
};
/**
* opaque placeholder (type erasure)
* for implementation specific type info.
* Intended to be passed to a concrete
* MediaImplLib to build an ImplFacade.
*/
class StreamType::ImplFacade::TypeTag
{
void* rawTypeStruct_;
public:
Symbol libraryID;
template<class TY>
TypeTag (Symbol lID, TY& rawType)
: rawTypeStruct_(&rawType),
libraryID(lID)
{ }
};
} // namespace lumiera
#endif

View file

@ -20,22 +20,20 @@ noinst_LIBRARIES += liblumi.a
liblumi_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror
liblumi_a_SOURCES = \
$(liblumi_a_srcdir)/plugin.c \
$(liblumi_a_srcdir)/error.c \
$(liblumi_a_srcdir)/mutex.c \
$(liblumi_a_srcdir)/rwlock.c \
$(liblumi_a_srcdir)/condition.c \
$(liblumi_a_srcdir)/luid.c \
$(liblumi_a_srcdir)/safeclib.c \
$(liblumi_a_srcdir)/cuckoo.c \
$(liblumi_a_srcdir)/psplay.c \
$(liblumi_a_srcdir)/mrucache.c \
$(liblumi_a_srcdir)/time.c \
liblumi_a_SOURCES = \
$(liblumi_a_srcdir)/error.c \
$(liblumi_a_srcdir)/mutex.c \
$(liblumi_a_srcdir)/rwlock.c \
$(liblumi_a_srcdir)/condition.c \
$(liblumi_a_srcdir)/luid.c \
$(liblumi_a_srcdir)/safeclib.c \
$(liblumi_a_srcdir)/cuckoo.c \
$(liblumi_a_srcdir)/psplay.c \
$(liblumi_a_srcdir)/mrucache.c \
$(liblumi_a_srcdir)/time.c \
$(liblumi_a_srcdir)/appconfig.cpp
noinst_HEADERS += \
$(liblumi_a_srcdir)/plugin.h \
$(liblumi_a_srcdir)/error.h \
$(liblumi_a_srcdir)/mutex.h \
$(liblumi_a_srcdir)/rwlock.h \
@ -46,6 +44,7 @@ noinst_HEADERS += \
$(liblumi_a_srcdir)/psplay.h \
$(liblumi_a_srcdir)/mrucache.h \
$(liblumi_a_srcdir)/time.h \
$(liblumi_a_srcdir)/ppmpl.h \
$(liblumi_a_srcdir)/appconfig.hpp \
$(liblumi_a_srcdir)/lifecycleregistry.hpp

71
src/lib/external/libgavl.cpp vendored Normal file
View file

@ -0,0 +1,71 @@
/*
ImplFacadeGAVL - facade for integrating the GAVL media handling library
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
#include "proc/lumiera.hpp"
#include "lib/external/libgavl.hpp"
#include "proc/control/stypemanager.hpp"
extern "C" {
#include <gavl/gavl.h>
}
namespace lib {
namespace external {
using control::STypeManager;
using control::ON_STREAMTYPES_RESET;
using lumiera::LifecycleHook;
void
provide_GAVL_stream_implementation_types ()
{
STypeManager& typeManager = STypeManager::instance();
UNIMPLEMENTED ("wire up a ImplFacade for GAVL implemented media streams");
}
namespace { // internal functionality
LifecycleHook _register_gavl_types_ (ON_STREAMTYPES_RESET, &provide_GAVL_stream_implementation_types);
}
/**
* Use an type information struct, which actually has to be
* a GAVL frametype (TODO), to wire up an ImplFacade such
* as to deal with GAVL data frames of this type.
* @todo fill in the acutal GAVL frame type
* @todo how to distinguish the audio and the video case?
*/
ImplFacadeGAVL const&
LibGavl::getImplFacade (TypeTag&)
{
TODO ("any chance to verify that the TypeTag actually points to a GAVL frame type descriptor?");
UNIMPLEMENTED ("wire up an impl facade with the correct GAVL lib functions for the data type in question");
}
} // namespace external
} // namespace lib

90
src/lib/external/libgavl.hpp vendored Normal file
View file

@ -0,0 +1,90 @@
/*
LILBGAVL.hpp - facade for integrating the GAVL media handling library
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LIB_EXTERN_LIBGAVL_H
#define LIB_EXTERN_LIBGAVL_H
#include "proc/control/mediaimpllib.hpp"
namespace lib {
namespace external {
using lumiera::Symbol;
using lumiera::StreamType;
typedef StreamType::ImplFacade ImplFacade;
typedef StreamType::ImplFacade::TypeTag TypeTag;
class LibGavl;
/**
* Concrete media lib implementation facade
* allowing to work with GAVL data frames and types
* in an implementation agnostic way.
* @note GAVL types are automagically registered into the
* control::STypeManager on reset and thus are always available.
*/
class ImplFacadeGAVL
: public ImplFacade
{
protected:
ImplFacadeGAVL()
: ImplFacade("GAVL")
{ }
friend class LibGavl;
public:
virtual bool operator== (ImplFacade const& other) const;
virtual bool operator== (StreamType const& other) const;
virtual bool canConvert (ImplFacade const& other) const;
virtual bool canConvert (StreamType const& other) const;
virtual StreamType::MediaKind getKind() const;
virtual DataBuffer* createFrame () const;
};
class LibGavl
: public control::MediaImplLib
{
protected:
public:
virtual Symbol getLibID() const { return "GAVL"; }
virtual ImplFacadeGAVL const& getImplFacade (TypeTag&);
};
} // namespace external
} // namespace lib
#endif

View file

@ -31,6 +31,22 @@
*/
typedef unsigned char lumiera_uid[16];
typedef lumiera_uid* LumieraUid;
/*
C++ can't initialize arrays from string literals with the trailing \0 cropped
C can't initialize non constant members,
there we go
*/
#ifdef __cplusplus
#define LUMIERA_UID_INITIALIZER(l) \
{ \
l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], \
l[8], l[9], l[10], l[11], l[12], l[13], l[14], l[15] \
}
#else
#define LUMIERA_UID_INITIALIZER(l) l
#endif
/**
* Retrieve a generic pointer stored in a luid

View file

@ -44,6 +44,30 @@ lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* f
}
static pthread_once_t recursive_mutexattr_once = PTHREAD_ONCE_INIT;
static pthread_mutexattr_t recursive_mutexattr;
static void recursive_mutexattr_init()
{
pthread_mutexattr_init (&recursive_mutexattr);
pthread_mutexattr_settype (&recursive_mutexattr, PTHREAD_MUTEX_RECURSIVE);
}
LumieraMutex
lumiera_recmutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag)
{
if (self)
{
pthread_once(&recursive_mutexattr_once, recursive_mutexattr_init);
pthread_mutex_init (&self->mutex, &recursive_mutexattr);
NOBUG_RESOURCE_HANDLE_INIT (self->rh);
NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "recmutex", purpose, self, self->rh);
}
return self;
}
LumieraMutex
lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag)
{

View file

@ -39,15 +39,78 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
/**
* Mutual exclusive section.
*/
#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \
for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \
#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \
for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ \
= {(LumieraMutex)1 NOBUG_RESOURCE_HANDLE_COMMA_INITIALIZER}; \
lumiera_mutex_section_.mutex;) \
for ( \
({ \
lumiera_mutex_section_.mutex = (mtx); \
NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_mutex_section_, \
NOBUG_RESOURCE_EXCLUSIVE, lumiera_mutex_section_.rh); \
if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
}); \
lumiera_mutex_section_.mutex; \
({ \
if (lumiera_mutex_section_.mutex) \
{ \
pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \
lumiera_mutex_section_.mutex = NULL; \
RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \
} \
}))
/**
* Mutual exclusion chainbuilder section.
* Usage: LUMIERA_MUTEX_SECTION(a){LUMIERA_MUTEX_SECTION_CHAIN(b){run();}}
* calls lock(a); lock(b); unlock(a); run(); unlock(b);
* This macro should only be used inside LUMIERA_MUTEX_SECTION and should be
* called on the correct mutexes, period.
*/
#define LUMIERA_MUTEX_SECTION_CHAIN(nobugflag, mtx) \
for (lumiera_mutexacquirer *lumiera_mutex_section_old_ = &lumiera_mutex_section_, \
NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1 \
NOBUG_RESOURCE_HANDLE_COMMA_INITIALIZER}; \
lumiera_mutex_section_.mutex;) \
for ( \
({ \
lumiera_mutex_section_.mutex = (mtx); \
NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_mutex_section_, \
NOBUG_RESOURCE_EXCLUSIVE, lumiera_mutex_section_.rh); \
if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
if (lumiera_mutex_section_old_->mutex) \
{ \
pthread_mutex_unlock (&lumiera_mutex_section_old_->mutex->mutex); \
lumiera_mutex_section_old_->mutex = NULL; \
RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_old_->rh); \
} \
}); \
lumiera_mutex_section_.mutex; \
({ \
if (lumiera_mutex_section_.mutex) \
{ \
pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \
lumiera_mutex_section_.mutex = NULL; \
RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \
} \
}))
/**
* Recursive Mutual exclusive section.
*/
#define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx) \
for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1 \
NOBUG_RESOURCE_HANDLE_COMMA_INITIALIZER}; \
lumiera_mutex_section_.mutex;) \
for ( \
({ \
lumiera_mutex_section_.mutex = (mtx); \
NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_mutex_section_, \
NOBUG_RESOURCE_EXCLUSIVE, lumiera_mutex_section_.rh); \
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", &lumiera_mutex_section_, \
NOBUG_RESOURCE_RECURSIVE, lumiera_mutex_section_.rh); \
if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
}); \
lumiera_mutex_section_.mutex; \
@ -61,6 +124,43 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
}))
/**
* Mutual exclusion chainbuilder section.
* Usage: LUMIERA_MUTEX_SECTION(a){LUMIERA_RECMUTEX_SECTION_CHAIN(b){run();}}
* calls lock(a); lock(b); unlock(a); run(); unlock(b);
* This macro should only be used inside LUMIERA_MUTEX_SECTION and should be
* called on the correct mutexes, period.
*/
#define LUMIERA_RECMUTEX_SECTION_CHAIN(nobugflag, mtx) \
for (lumiera_mutexacquirer *lumiera_mutex_section_old_ = &lumiera_mutex_section_, \
NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1 \
NOBUG_RESOURCE_HANDLE_COMMA_INITIALIZER}; \
lumiera_mutex_section_.mutex;) \
for ( \
({ \
lumiera_mutex_section_.mutex = (mtx); \
NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", &lumiera_mutex_section_, \
NOBUG_RESOURCE_RECURSIVE, lumiera_mutex_section_.rh); \
if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
if (lumiera_mutex_section_old_->mutex) \
{ \
pthread_mutex_unlock (&lumiera_mutex_section_old_->mutex->mutex); \
lumiera_mutex_section_old_->mutex = NULL; \
RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_old_->rh); \
} \
}); \
lumiera_mutex_section_.mutex; \
({ \
if (lumiera_mutex_section_.mutex) \
{ \
pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \
lumiera_mutex_section_.mutex = NULL; \
RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \
} \
}))
/**
* Mutex.
*
@ -76,12 +176,22 @@ typedef lumiera_mutex* LumieraMutex;
/**
* Initialize a mutex variable
* This initializes a 'fast' default mutex which must not be locked recursively from one thread.
* @param self is a pointer to the mutex to be initialized
* @return self as given
*/
LumieraMutex
lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag);
/**
* Initialize a mutex variable
* Initializes a 'recursive' mutex which might be locked by the same thread multiple times.
* @param self is a pointer to the mutex to be initialized
* @return self as given
*/
LumieraMutex
lumiera_recmutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag);
/**
* Destroy a mutex variable

158
src/lib/ppmpl.h Normal file
View file

@ -0,0 +1,158 @@
/*
ppmpl.h - preprocessor meta programming library
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef PPMPL_H
#define PPMPL_H
/**
* @file
* Preprocessor metaprogramming library. We define some useful preprocessor
* tricks here.
*/
/**
* Iterate over a list of macros.
* @param p used to disambiguate up to three passes, use _, _P1_ or _P2_
* @param ... list of macros to be expanded. The user has to supply a definition
* in the form of PPMPL_FOREACH##p##macroname which shall expand to the desired text.
*
* This user defined macro shall be undefed after use.
*
* @example
* #define PPMPL_FOREACH_P1_FOO(arg) arg,
*
* {PPMPL_FOREACH(P1, FOO(1), FOO(2), FOO(3)), -1}
*
* #undef PPMPL_FOREACH_P1_FOO
*
* Would expand to the sequence:
* {1, 2, 3, -1}
*
* One can not recursively nest preprocessor macros. To allow this we define PPMPL_FOREACH_L1
* to PPMPL_FOREACH_L2 with the same semantics as PPMPL_FOREACH, This allowes to nest the
* FOREACH loop up to three nesting levels.
*/
#define PPMPL_FOREACH(p, ...) PPMPL_FOREACH0(p, __VA_ARGS__, PPMPL_FOREACH_NIL))
/* internal */
#define PPMPL_FOREACH0(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH1(p, __VA_ARGS__)
#define PPMPL_FOREACH1(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH2(p, __VA_ARGS__)
#define PPMPL_FOREACH2(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH3(p, __VA_ARGS__)
#define PPMPL_FOREACH3(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH4(p, __VA_ARGS__)
#define PPMPL_FOREACH4(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH5(p, __VA_ARGS__)
#define PPMPL_FOREACH5(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH6(p, __VA_ARGS__)
#define PPMPL_FOREACH6(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH7(p, __VA_ARGS__)
#define PPMPL_FOREACH7(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH8(p, __VA_ARGS__)
#define PPMPL_FOREACH8(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH9(p, __VA_ARGS__)
#define PPMPL_FOREACH9(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH10(p, __VA_ARGS__)
#define PPMPL_FOREACH10(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH11(p, __VA_ARGS__)
#define PPMPL_FOREACH11(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH12(p, __VA_ARGS__)
#define PPMPL_FOREACH12(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH13(p, __VA_ARGS__)
#define PPMPL_FOREACH13(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH14(p, __VA_ARGS__)
#define PPMPL_FOREACH14(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH15(p, __VA_ARGS__)
#define PPMPL_FOREACH15(p, h, ...) PPMPL_FOREACH##p##h
#define PPMPL_FOREACH_
#define PPMPL_FOREACH_P1_
#define PPMPL_FOREACH_P2_
#define PPMPL_FOREACH_PPMPL_FOREACH_NIL PPMPL_FOREACH_FINAL(
#define PPMPL_FOREACH_P1_PPMPL_FOREACH_NIL PPMPL_FOREACH_FINAL(
#define PPMPL_FOREACH_P2_PPMPL_FOREACH_NIL PPMPL_FOREACH_FINAL(
#define PPMPL_FOREACH_FINAL(...)
#define PPMPL_FOREACH_L1(p, ...) PPMPL_FOREACH_L1_0(p, __VA_ARGS__, PPMPL_FOREACH_L1_NIL))
/* internal */
#define PPMPL_FOREACH_L1_0(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_1(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_1(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_2(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_2(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_3(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_3(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_4(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_4(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_5(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_5(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_6(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_6(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_7(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_7(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_8(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_8(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_9(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_9(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_10(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_10(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_11(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_11(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_12(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_12(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_13(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_13(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_14(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_14(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_15(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_15(p, h, ...) PPMPL_FOREACH_L1##p##h
#define PPMPL_FOREACH_L1_
#define PPMPL_FOREACH_L1_P1_
#define PPMPL_FOREACH_L1_P2_
#define PPMPL_FOREACH_L1_PPMPL_FOREACH_L1_NIL PPMPL_FOREACH_L1_FINAL(
#define PPMPL_FOREACH_L1_P1_PPMPL_FOREACH_L1_NIL PPMPL_FOREACH_L1_FINAL(
#define PPMPL_FOREACH_L1_P2_PPMPL_FOREACH_L1_NIL PPMPL_FOREACH_L1_FINAL(
#define PPMPL_FOREACH_L1_FINAL(...)
#define PPMPL_FOREACH_L2(p, ...) PPMPL_FOREACH_L2_0(p, __VA_ARGS__, PPMPL_FOREACH_L2_NIL))
/* internal */
#define PPMPL_FOREACH_L2_0(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_1(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_1(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_2(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_2(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_3(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_3(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_4(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_4(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_5(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_5(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_6(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_6(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_7(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_7(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_8(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_8(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_9(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_9(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_10(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_10(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_11(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_11(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_12(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_12(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_13(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_13(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_14(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_14(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_15(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_15(p, h, ...) PPMPL_FOREACH_L2##p##h
#define PPMPL_FOREACH_L2_
#define PPMPL_FOREACH_L2_P1_
#define PPMPL_FOREACH_L2_P2_
#define PPMPL_FOREACH_L2_PPMPL_FOREACH_L2_NIL PPMPL_FOREACH_L2_FINAL(
#define PPMPL_FOREACH_L2_P1_PPMPL_FOREACH_L2_NIL PPMPL_FOREACH_L2_FINAL(
#define PPMPL_FOREACH_L2_P2_PPMPL_FOREACH_L2_NIL PPMPL_FOREACH_L2_FINAL(
#define PPMPL_FOREACH_L2_FINAL(...)
/**
* Canonical preprocessor concat implementation which evaluates its arguments
*/
#define PPMPL_CAT(a,b) PPMPL_CAT_(a,b)
#define PPMPL_CAT_(a,b) a##b
#define PPMPL_STRINGIFY(a) PPMPL_STRINGIFY_(a)
#define PPMPL_STRINGIFY_(a) #a
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -51,6 +51,7 @@ struct psplaynode_struct
PSplaynode right;
};
#define PSPLAYNODE_INITIALIZER {NULL, NULL}
/**
* Function use to compare keys

View file

@ -51,6 +51,17 @@ lumiera_calloc (size_t n, size_t size)
}
void*
lumiera_realloc (void* ptr, size_t size)
{
void* o = size ? realloc (ptr, size) : NULL;
if (!o)
LUMIERA_DIE (NO_MEMORY);
return o;
}
char*
lumiera_strndup (const char* str, size_t len)
{

View file

@ -50,6 +50,16 @@ void*
lumiera_calloc (size_t n, size_t size);
/**
* Change the size of a memory block.
* @param ptr pointer to the old memory block obtained by lumiera_malloc or lumiera_calloc
* @param size new size of the block
* @return address of new block
*/
void*
lumiera_realloc (void* ptr, size_t size);
/**
* Free previously allocated memory.
* @param mem pointer to the memory block obtained by lumiera_malloc or lumiera_calloc

View file

@ -74,7 +74,7 @@ namespace asset
/**
* key abstraction: structural asset
* @todo just a stub, have to figure out what a asset::Proc is
* @todo just a stub, have to figure out what a asset::Struct is
*/
class Struct : public Asset
{

View file

@ -0,0 +1,54 @@
/*
MEDIAIMPLLIB.hpp - interface providing a facade to an media handling library
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef CONTROL_MEDIAIMPLLIB_H
#define CONTROL_MEDIAIMPLLIB_H
#include "common/streamtype.hpp"
namespace control {
using lumiera::Symbol;
class MediaImplLib
{
protected:
virtual ~MediaImplLib() {};
typedef lumiera::StreamType::ImplFacade ImplFacade;
typedef lumiera::StreamType::ImplFacade::TypeTag TypeTag;
typedef lumiera::StreamType::ImplFacade::DataBuffer DataBuffer;
public:
virtual Symbol getLibID() const =0;
virtual ImplFacade const& getImplFacade (TypeTag&) =0;
};
} // namespace control
#endif

View file

@ -21,23 +21,19 @@
* *****************************************************/
#include "proc/mobject/controller/pathmanager.hpp"
#include "proc/control/pathmanager.hpp"
namespace mobject
namespace control {
engine::Processor *
PathManager::buildProcessor ()
{
namespace controller
{
UNIMPLEMENTED ("build a complete processor and optimize render path");
return 0;//////////////////TODO
}
engine::Processor *
PathManager::buildProcessor ()
{
return 0;//////////////////TODO
}
} // namespace mobject::controller
} // namespace mobject
} // namespace control

View file

@ -21,34 +21,29 @@
*/
#ifndef MOBJECT_CONTROLLER_PATHMANAGER_H
#define MOBJECT_CONTROLLER_PATHMANAGER_H
#ifndef CONTROL_PATHMANAGER_H
#define CONTROL_PATHMANAGER_H
#include "proc/engine/processor.hpp"
namespace mobject
{
namespace controller
namespace control {
/**
* While building a render engine, this Strategy class
* decides on the actual render strategy in accordance
* to the current controller settings (system state)
*/
class PathManager
{
/**
* While building a render engine, this Strategy class
* decides on the actual render strategy in accordance
* to the current controller settings (system state)
*/
class PathManager
{
public:
engine::Processor* buildProcessor () ;
// TODO: allocation, GC??
};
public:
engine::Processor* buildProcessor () ;
// TODO: allocation, GC??
};
} // namespace mobject::controller
} // namespace mobject
} // namespace control
#endif

View file

@ -21,38 +21,33 @@
*/
#ifndef MOBJECT_CONTROLLER_RENDERSTATE_H
#define MOBJECT_CONTROLLER_RENDERSTATE_H
#ifndef CONTROL_RENDERSTATE_H
#define CONTROL_RENDERSTATE_H
#include "proc/state.hpp"
namespace mobject
{
namespace controller
namespace control {
typedef proc_interface::State State;
/**
* Encapsulates the logic used to get a "current render process"
* in accordance to the currently applicable controller settings.
* The provided StateProxy serves to hold any mutalbe state used
* in the render process, so the rest of the render engine
* can be stateless.
* @todo probably the state management will work different (6/08)
*/
class RenderState
{
typedef proc_interface::State State;
/**
* Encapsulates the logic used to get a "current render process"
* in accordance to the currently applicable controller settings.
* The provided StateProxy serves to hold any mutalbe state used
* in the render process, so the rest of the render engine
* can be stateless.
* @todo probably the state management will work different (6/08)
*/
class RenderState
{
public:
State& getRenderProcess () ;
};
public:
State& getRenderProcess () ;
};
} // namespace mobject::controller
} // namespace mobject
} // namespace control
#endif

View file

@ -0,0 +1,117 @@
/*
STypeManager - entry point for dealing with media stream types
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
#include "proc/lumiera.hpp"
#include "proc/control/stypemanager.hpp"
#include "proc/control/styperegistry.hpp"
namespace control {
using lumiera::StreamType;
using lumiera::Symbol;
/* ======= stream type manager lifecycle ==========*/
STypeManager::STypeManager()
: reg_(0)
{
reset();
}
STypeManager::~STypeManager()
{ }
/** access the system-wide stream type manager instance.
* Implemented as singleton. */
lumiera::Singleton<STypeManager> STypeManager::instance;
void
STypeManager::reset()
{
reg_.reset(new Registry);
lumiera::Appconfig::lifecycle(ON_STREAMTYPES_RESET);
}
/** \par
* LifecycleHook, on which all the basic setup and configuration
* providing the pristine state of the stream type system has to be registered.
* @note plugins providing additional streamtype configuration should register
* their basic setup functions using this hook, which can be done via
* the C interface functions
*/
Symbol ON_STREAMTYPES_RESET ("ON_STREAMTYPES_RESET");
/* ======= implementation of the public interface ========= */
/** */
StreamType const&
STypeManager::getType (Symbol sTypeID)
{
UNIMPLEMENTED ("get type just by symbolic ID (query defaults manager)");
}
StreamType const&
STypeManager::getType (StreamType::Prototype const& protoType)
{
UNIMPLEMENTED ("build complete StreamType based on prototype; may include querying defaults manager");
}
StreamType const&
STypeManager::getType (StreamType::ImplFacade const& implType)
{
UNIMPLEMENTED ("build complete StreamType round the given implementation type");
}
StreamType::ImplFacade const&
STypeManager::getImpl (Symbol libID, StreamType::Prototype const& protoType)
{
UNIMPLEMENTED ("wire up implementation in compliance to a prototype and using a specific MediaImplLib. really tricky.... ");
}
StreamType::ImplFacade const&
STypeManager::fetchImpl (StreamType::ImplFacade::TypeTag rawType)
{
UNIMPLEMENTED ("STypeManager basic functionality: wire up implementation facade (impl type) from given raw type of the library");
}
} // namespace control
// ==== C interface for registering setup of basic stream type configuration =======
void
lumiera_StreamType_registerInitFunction (void setupFun(void))
{
lumiera::LifecycleHook (control::ON_STREAMTYPES_RESET, setupFun);
}

View file

@ -0,0 +1,129 @@
/*
STYPEMANAGER.hpp - entry point for dealing with media stream types
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef CONTROL_STYPEMANAGER_H
#define CONTROL_STYPEMANAGER_H
#include "common/streamtype.hpp"
#include "common/singleton.hpp"
#include <boost/scoped_ptr.hpp>
namespace control {
using lumiera::Symbol;
using lumiera::StreamType;
class STypeManager
{
class Registry;
boost::scoped_ptr<Registry> reg_;
public:
static lumiera::Singleton<STypeManager> instance;
typedef StreamType::ImplFacade ImplFacade;
/** (re)-access a media stream type using
* just a symbolic ID. Effectively this queries a default */
StreamType const& getType (Symbol sTypeID) ;
/** build or retrieve a complete StreamType implementing the given Prototype */
StreamType const& getType (StreamType::Prototype const& protoType) ;
/** build or retrieve a complete StreamType incorporating the given implementation type */
StreamType const& getType (StreamType::ImplFacade const& implType) ;
/** build or retrieve an implementation (facade)
* utilizing a specific MediaImplLib and implementing the given Prototype.
* @todo find out if this one is really necessary, because it is especially tricky */
ImplFacade const& getImpl (Symbol libID, StreamType::Prototype const& protoType) ;
/** build or retrieve an implementation (facade)
* wrapping up the actual implementation as designated by the rawType tag,
* which needs to be an implementation type of the mentioned MediaImplLib */
template<class TY>
ImplFacade const& getImpl (Symbol libID, TY& rawType) ;
////////////////TODO: design a mechanism allowing to add MediaImplLib implementations by plugin......
protected:
STypeManager() ;
~STypeManager();
friend class lumiera::singleton::StaticCreate<STypeManager>;
/** Lifecycle: reset all type registration information
* to the <i>generic pristine default</i> state. This includes
* hard wired defaults and defauls provided by type plugins, but
* excludes everything added by the session
*/
void reset() ;
private:
ImplFacade const& fetchImpl (StreamType::ImplFacade::TypeTag);
};
extern Symbol ON_STREAMTYPES_RESET; ///< triggered to load the generic pristine default
template<class TY>
StreamType::ImplFacade const&
STypeManager::getImpl (Symbol libID, TY& rawType)
{
return fetchImpl (ImplFacade::TypeTag (libID,rawType));
}
} // namespace control
namespace proc_interface {
using control::STypeManager;
} // namespace proc_interface
extern "C" { //TODO provide a separate header if some C code or plugin happens to need this...
/** any stream type implementation, which needs to be present on the
* pristine default level (without any session specific configuration),
* should register a setup function, which will be called on each
* STypemanager::reset()
*/
void
lumiera_StreamType_registerInitFunction (void setupFun(void));
// TODO provide a C interface usable from such a setupFun to access the STypeManager registration functions.
}
#endif

View file

@ -0,0 +1,86 @@
/*
STYPEREGISTRY.hpp - implementation of the registry for stream type descriptors
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file styperegistry.hpp
** This is part of the \i implementation of the stream type manager (include).
** Only used in stypemanager.cpp and accompaning unit tests.
**
** @see control::STypeManager
** @see lumiera::StreamType
**
*/
#ifndef CONTROL_STYPEREGISTRY_H
#define CONTROL_STYPEREGISTRY_H
//#include "common/query.hpp"
//#include "common/util.hpp"
//#include "common/p.hpp"
//#include <set>
//#include <vector>
//#include <tr1/memory>
//#include <boost/format.hpp>
#include <boost/noncopyable.hpp>
namespace control {
// using lumiera::P;
// using lumiera::Query;
// using std::string;
// using boost::format;
namespace impl {
} // (End) impl namespace
/**
* @internal Helper for organizing preconfigured default objects.
* Maintaines a collection of objects known or encountered as "default"
* for a given type. This collection is ordered by "degree of constriction",
* which is implemented by counting the number of predicates in the query
* used to define or identify each object.
* Accessing an object identified by a query causes the query to be resolved
* (executed in prolog), which may result in some additional properties of
* the object being bound or specified.
* @todo as of 3/2008 the real query implementation is missing, and the
* exact behaviour has to be defined.
*/
class STypeManager::Registry : private boost::noncopyable
{
public:
};
} // namespace control
#endif

View file

@ -40,6 +40,7 @@
#include "common/error.hpp"
#include "common/streamtype.hpp"
namespace engine {
@ -52,7 +53,7 @@ namespace engine {
*/
struct BuffHandle
{
typedef float Buff;
typedef lumiera::StreamType::ImplFacade::DataBuffer Buff;
typedef Buff* PBuff;//////TODO define the Buffer type(s)
PBuff

View file

@ -19,6 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file nodewiringconfig.hpp
** Sometimes we need to coose a different implementation for dealing with
** some special cases. While for simple cases, just testing a flag or using a
@ -44,6 +45,8 @@
** @see configflags.hpp
**
*/
#ifndef ENGINE_NODEWIRINGCONFIG_H
#define ENGINE_NODEWIRINGCONFIG_H

View file

@ -61,7 +61,7 @@ namespace engine {
typedef ProcNode* PNode;
template<class E>
struct RefArray
struct RefArray ///< @todo need an implementation and then probably move it into library
{
virtual E const& operator[] (uint i) const =0;
virtual ~RefArray() {}

View file

@ -22,6 +22,18 @@
*/
/** @file lumiera.hpp
** Basic set of definitions and includes commonly used together.
** Including lumiera.hpp gives you a common set of elementary declarations
** widely used within the C++ code of the Proc-Layer.
**
** @see main.cpp
** @see pre.hpp
**
*/
#ifndef LUMIERA_H
#define LUMIERA_H
@ -37,11 +49,67 @@
#include "lib/appconfig.hpp"
namespace lumiera
{
/* additional global configuration goes here... */
/**
* Namespace for globals.
* A small number of definitions and facilities of application wide relevance.
* It's probably a good idea to pull it in explicitly and to avoid nesting
* implementation namespaces within \c lumiera::
*/
namespace lumiera {
/* additional global configuration goes here... */
} // namespace lumiera
/**
* Namespace for support and library code.
*/
namespace lib {
}
/**
* The asset subsystem of the Proc-Layer.
*/
namespace asset { }
/**
* Proc-Layer dispatcher, controller and administrative facilities.
*/
namespace control { }
/**
* Render engine code as part of the Proc-Layer.
* Backbone of the engine, render nodes base and cooperation.
* A good deal of the active engine code is outside the scope of the
* Proc-Layer, e.g. code located in backend services and plugins.
*/
namespace engine { }
/**
* Media-Objects, edit operations and high-level session.
*/
namespace mobject {
/**
* Namespace of Session, EDL and user visible high-level objects.
*/
namespace session { }
/**
* Namespace of the Builder, transforming high-level into low-level.
*/
namespace builder { }
}
#endif /*LUMIERA_H*/

View file

@ -1,5 +1,5 @@
/*
ConManager - manages the creation of additional ProcNode connections for the Renderengine
ConManager - manages the creation of data/control connections when building the Renderengine
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
@ -22,15 +22,13 @@
#include "proc/mobject/builder/conmanager.hpp"
#include "proc/control/stypemanager.hpp"
namespace mobject
{
namespace builder
{
namespace mobject {
namespace builder {
/**
* TODO !!!!!!!!!!!!!!!!!!
*/

View file

@ -1,5 +1,5 @@
/*
CONMANAGER.hpp - manages the creation of additional ProcNode connections for the Renderengine
CONMANAGER.hpp - manages the creation of data/control connections when building the Renderengine
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
@ -26,17 +26,20 @@
namespace mobject
{
namespace builder
{
namespace mobject {
namespace builder {
/**
* Connection Manager: used to build the connections between render engine nodes
* if these nodes need to cooperate besides the normal "data pull" operation.
* Esp. the Connection Manager knows how to wire up the effect's parameters
* with the corresponding ParamProviders (autmation) in the Session.
* Questions regarding the possibility of a media stream connection are
* delegated internally to the STypeManager.
* \par
* The primary service of the connection manager is to accept a wiring request
* and handle the details of establishing the necessary connections.
*/
class ConManager
{

View file

@ -0,0 +1,54 @@
/*
WIRINGREQUEST.hpp - (interface) the intention to make a data or control connection
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef MOBJECT_BUILDER_WIRINGREQUEST_H
#define MOBJECT_BUILDER_WIRINGREQUEST_H
namespace mobject {
namespace builder {
/**
* A stateful value object denoting the wish to establish a link or connection
* between two entities. Used to organize the proper working of the build process.
* Wiring requests are first to be checked and can be deemed impossible to
* satisfy. Internally, wiring requests contain specific information about
* the objects to be connected. This information is exposed only to the
* ConManager, which is the facility actually wiring the connections.
*/
class WiringRequest
{
public:
/**
* TODO design sketch......
*/
};
} // namespace mobject::builder
} // namespace mobject
#endif

View file

@ -20,101 +20,21 @@
using std::string;
using std::cout;
using std::ostream;
using boost::format;
#include <boost/utility/enable_if.hpp>
using boost::enable_if;
#include <boost/type_traits/is_base_of.hpp>
using boost::is_base_of;
#include <boost/type_traits/is_abstract.hpp>
#include <boost/type_traits/is_polymorphic.hpp>
#include "common/meta/generator.hpp"
using lumiera::typelist::NullType;
using lumiera::typelist::Node;
using lumiera::typelist::Types;
namespace {
boost::format fmt ("<%2i>");
/** constant-wrapper type for debugging purposes,
* usable for generating lists of distinghishable types
*/
template<int I>
struct Num
{
enum{ VAL=I };
static string str () { return boost::str (fmt % I); }
Num()
{
cout << Num::str();
}
};
template<template<class> class _CandidateTemplate_>
class Instantiation
{
template<class ARG>
struct If_possibleArgument : _CandidateTemplate_<ARG>
{
typedef void Type;
};
public:
template<class X, class TEST=void>
struct Test
: boost::false_type {};
template<class X>
struct Test<X, typename If_possibleArgument<X>::Type >
: boost::true_type {};
};
}
struct Boing { typedef boost::true_type is_defined; };
template<int> struct Zoing ;
template<> struct Zoing<2> : Boing { enum{wau = 2}; };
template<> struct Zoing<5> : Boing { enum{wau = 5}; };
typedef char yes_type;
struct no_type
{
char padding[8];
};
template<class U>
yes_type check(typename U::is_defined *);
template<class U>
no_type check(...);
int
main (int argc, char* argv[])
{
NOBUG_INIT;
typedef Zoing<2> Z2;
typedef Zoing<3> Z3;
typedef Zoing<5> Z5;
cout << sizeof(check<Z2>(0)) << " / "
<< sizeof(check<Z3>(0)) << " / "
<< sizeof(check<Z5>(0)) ;
cout << "\ngulp\n";

View file

@ -18,6 +18,18 @@ out: inner mutex locked section
END
TEST "chained mutex section" chainedmutexsection <<END
out: outer mutex locked section
out: inner but not outer mutex locked section
END
TEST "recursive mutex section" recursivemutexsection <<END
out: mutex locked once
out: mutex locked twice
END
TEST "rwlock section" rwlocksection <<END
out: write locked section 1
out: read locked section 2

View file

@ -9,9 +9,12 @@ TEST "Allocating some memory" allocation1024 <<END
return: 0
END
# seems that exit codes are not table here, was
# seems that exit codes are not stable here, was
# return: 134 before, needs to be fixed with improved testsuite
TEST "Allocation error" allocationtoobig <<END
#
# indeed: I get return value 134 both on etch and lenny
# thus I disabled this test for now (Ichthyo)
PLANNED "Allocation error" allocationtoobig <<END
return: 139
END

View file

@ -21,6 +21,73 @@ out: delim = '='
out: value = ' baz'
END
TEST "reset a value" change_value foo.bar '=foo' '=bar' <<END
out: foo
out: bar
END
TEST "create configitem with empty line" configitem_simple_ctor_dtor '' <<END
END
TEST "create configitem with blank line" configitem_simple_ctor_dtor $' \t \t' <<END
END
TEST "create configitem with comment" configitem_simple_ctor_dtor $' #\t comment bla' <<END
END
TEST "create configitem with section" configitem_simple_ctor_dtor $'\t[prefix suffix ] bla' <<END
END
TEST "create configitem with directive" configitem_simple_ctor_dtor $' @include \t\t file \t' <<END
END
TEST "create configitem with configentry" configitem_simple_ctor_dtor $' key \t=\t value' <<END
END
TEST "create configitem with configentry (redirect)" configitem_simple_ctor_dtor $'keya <\t\t keyb ' <<END
END
TEST "check content of configitem with empty line" configitem_simple_content_check $'' << END
END
TEST "check content of configitem with comment" configitem_simple_content_check $'\t #comment bla' << END
out: item->line = ' #comment bla'
END
TEST "check content of configitem with section" configitem_simple_content_check $'[ key.foo suffix.bar ] ' << END
out: item->line = '[ key.foo suffix.bar ] '
out: item->key_size = '7'
out: item->key = 'key.foo suffix.bar ] '
out: item->delim = ' suffix.bar ] '
END
TEST "check content of configitem with directive (without argument)" configitem_simple_content_check $'\t @directive ' << END
out: item->line = ' @directive '
out: item->key_size = '9'
out: item->key = '@directive '
END
TEST "check content of configitem with directive (with argument)" configitem_simple_content_check $'\t @directive \targument' << END
out: item->line = ' @directive argument'
out: item->key_size = '9'
out: item->key = '@directive argument'
out: item->delim = ' argument'
END
TEST "check content of configitem with configentry" configitem_simple_content_check $' \t\t key.foo \t\t=\tbar' << END
out: item->line = ' key.foo = bar'
out: item->key_size = '7'
out: item->key = 'key.foo = bar'
out: item->delim = '= bar'
END
TEST "check content of configitem with configentry (redirect)" configitem_simple_content_check $' \t\t key.foo \t\t<\tkey.bar' << END
out: item->line = ' key.foo < key.bar'
out: item->key_size = '7'
out: item->key = 'key.foo < key.bar'
out: item->delim = '< key.bar'
END
TEST "set a config and retrieve it" basic_set_get 'foo' '=bar' <<END
out: bar

View file

@ -1,6 +1,6 @@
TESTING "test plugin example code" ./test-plugin
TEST "C plugin example" C <<END
PLANNED "C plugin example" C <<END
out: opened
out: Hallo Welt!
out: Tschuess C
@ -11,7 +11,7 @@ out: closed
out: closed
END
TEST "C++ plugin example" C++ <<END
PLANNED "C++ plugin example" C++ <<END
out: opened
out: Hallo Welt!
out: Tschuess C++

View file

@ -131,64 +131,116 @@ END
PLANNED "bool set" <<END
END
TEST "create configitem with empty line" configitem_simple_ctor_dtor '' <<END
TEST "wordlist get item from empty list should fail" wordlist_get_nth 'foo.bar' '' 0 << END
out: 'NULL'
END
TEST "create configitem with blank line" configitem_simple_ctor_dtor $' \t \t' <<END
TEST "wordlist get item past end should fail" wordlist_get_nth 'foo.bar' 'baz barf gnarf' 3 << END
out: 'NULL'
END
TEST "create configitem with comment" configitem_simple_ctor_dtor $' #\t comment bla' <<END
TEST "wordlist get first item" wordlist_get_nth 'foo.bar' 'baz barf gnarf' 0 << END
out: 'baz'
END
TEST "create configitem with section" configitem_simple_ctor_dtor $'\t[prefix suffix ] bla' <<END
TEST "wordlist get last item" wordlist_get_nth 'foo.bar' 'baz barf; gnarf' 2 << END
out: 'gnarf'
END
TEST "create configitem with directive" configitem_simple_ctor_dtor $' @include \t\t file \t' <<END
TEST "wordlist get middle" wordlist_get_nth 'foo.bar' 'baz barf, gnarf' 1 << END
out: 'barf'
END
TEST "create configitem with configentry" configitem_simple_ctor_dtor $' key \t=\t value' <<END
TEST "wordlist find, non existing" wordlist_find 'foo.bar' 'baz barf, gnarf' blah << END
out: '-1'
END
TEST "create configitem with configentry (redirect)" configitem_simple_ctor_dtor $'keya <\t\t keyb ' <<END
TEST "wordlist find, first" wordlist_find 'foo.bar' 'baz barf, gnarf' baz << END
out: '0'
END
TEST "check content of configitem with empty line" configitem_simple_content_check $'' << END
TEST "wordlist find, middle" wordlist_find 'foo.bar' 'baz barf, gnarf' barf << END
out: '1'
END
TEST "check content of configitem with comment" configitem_simple_content_check $'\t #comment bla' << END
out: item->line = ' #comment bla'
TEST "wordlist find, last" wordlist_find 'foo.bar' 'baz barf, gnarf' gnarf << END
out: '2'
END
TEST "check content of configitem with section" configitem_simple_content_check $'[ key.foo suffix.bar ] ' << END
out: item->line = '[ key.foo suffix.bar ] '
out: item->key_size = '7'
out: item->key = 'key.foo suffix.bar ] '
out: item->delim = ' suffix.bar ] '
TEST "wordlist replace, middle, insert after" wordlist_replace 'foo.bar' 'baz barf gnarf' barf barf foof << END
out: ' baz barf foof gnarf'
END
TEST "check content of configitem with directive (without argument)" configitem_simple_content_check $'\t @directive ' << END
out: item->line = ' @directive '
out: item->key_size = '9'
out: item->key = '@directive '
TEST "wordlist replace, middle, insert before" wordlist_replace 'foo.bar' 'baz barf gnarf' barf foof barf << END
out: ' baz foof barf gnarf'
END
TEST "check content of configitem with directive (with argument)" configitem_simple_content_check $'\t @directive \targument' << END
out: item->line = ' @directive argument'
out: item->key_size = '9'
out: item->key = '@directive argument'
out: item->delim = ' argument'
TEST "wordlist replace, middle, remove" wordlist_replace 'foo.bar' 'baz barf gnarf' barf '' '' << END
out: ' baz gnarf'
END
TEST "check content of configitem with configentry" configitem_simple_content_check $' \t\t key.foo \t\t=\tbar' << END
out: item->line = ' key.foo = bar'
out: item->key_size = '7'
out: item->key = 'key.foo = bar'
out: item->delim = '= bar'
TEST "wordlist replace, middle, replace1" wordlist_replace 'foo.bar' 'baz barf gnarf' barf 'foof' '' << END
out: ' baz foof gnarf'
END
TEST "check content of configitem with configentry (redirect)" configitem_simple_content_check $' \t\t key.foo \t\t<\tkey.bar' << END
out: item->line = ' key.foo < key.bar'
out: item->key_size = '7'
out: item->key = 'key.foo < key.bar'
out: item->delim = '< key.bar'
TEST "wordlist replace, middle, replace2" wordlist_replace 'foo.bar' 'baz barf gnarf' barf '' 'foof' << END
out: ' baz foof gnarf'
END
TEST "wordlist replace, first, insert before" wordlist_replace 'foo.bar' 'baz barf gnarf' baz 'first' 'baz' << END
out: ' first baz barf gnarf'
END
TEST "wordlist replace, first, replace1" wordlist_replace 'foo.bar' 'baz barf gnarf' baz 'first' '' << END
out: ' first barf gnarf'
END
TEST "wordlist replace, first, replace2" wordlist_replace 'foo.bar' 'baz barf gnarf' baz '' 'first' << END
out: ' first barf gnarf'
END
TEST "wordlist replace, last, insert after" wordlist_replace 'foo.bar' 'baz barf gnarf' gnarf 'gnarf' 'last' << END
out: ' baz barf gnarf last'
END
TEST "wordlist add 2 words" wordlist_add 'foo.bar' 'baz barf gnarf' first second << END
out: ' baz barf gnarf first'
out: ' baz barf gnarf first second'
END
TEST "wordlist add same word" wordlist_add 'foo.bar' 'baz barf gnarf' same same << END
out: ' baz barf gnarf same'
out: ' baz barf gnarf same'
END
TEST "wordlist add to empty list" wordlist_add 'foo.bar' '' first second << END
out: ' first'
out: ' first second'
END
TEST "wordlist add to empty list, same" wordlist_add 'foo.bar' '' same same << END
out: ' same'
out: ' same'
END
TEST "wordlist get item from empty list should fail" wordlist_get_nth 'foo.bar' '' 0 << END
out: 'NULL'
END
TEST "wordlist get item past end should fail" wordlist_get_nth 'foo.bar' 'baz barf gnarf' 3 << END
out: 'NULL'
END
TEST "wordlist get first item" wordlist_get_nth 'foo.bar' 'baz barf gnarf' 0 << END
out: 'baz'
END
TEST "wordlist get last item" wordlist_get_nth 'foo.bar' 'baz barf; gnarf' 2 << END
out: 'gnarf'
END
TEST "wordlist get middle" wordlist_get_nth 'foo.bar' 'baz barf, gnarf' 1 << END
out: 'barf'
END

View file

@ -280,6 +280,14 @@ out: dtor ~TargetObj(24) successfull
END
PLANNED "StreamTypeBasics_test" StreamTypeBasics_test <<END
END
PLANNED "StreamTypeLifecycle_test" StreamTypeLifecycle_test <<END
END
TEST "TestOption_test" TestOption_test <<END
out: Testing invocation with cmdline: ...
out: --> Testgroup=ALL

View file

@ -48,6 +48,11 @@ test_luid_SOURCES = $(tests_srcdir)/library/test-luid.c
test_luid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_luid_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
check_PROGRAMS += test-interfaces
test_interfaces_SOURCES = $(tests_srcdir)/backend/test-interfaces.c
test_interfaces_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_interfaces_LDADD = liblumibackend.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
check_PROGRAMS += test-filedescriptors
test_filedescriptors_SOURCES = $(tests_srcdir)/backend/test-filedescriptors.c
test_filedescriptors_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror

View file

@ -36,26 +36,32 @@ def testCollection(env,dir):
""" treat a Directory containing a collection of standalone tests.
Link each of them into an independent executable
"""
srcpatt = ['test-*.c']
exeName = lambda p: path.basename(path.splitext(p)[0])
buildIt = lambda p: env.Program("#$BINDIR/"+exeName(p), [p] + core)
return [buildIt(f) for f in scanSubtree(dir)]
return [buildIt(f) for f in scanSubtree(dir,srcpatt)]
def treatPluginTestcase(env):
""" Special case: the test-plugin executable
"""
tree = 'backend'
env = env.Clone()
env.Append(CPPPATH='plugin')
prfx = 'plugin/example_plugin'
env.Append(CPPPATH=tree)
prfx = path.join(tree,'example_plugin')
oC = env.SharedObject(prfx, prfx+'.c')
oCPP = env.SharedObject(prfx+'_cpp', prfx+'.cpp')
testplugin = ( env.SharedLibrary('#$BINDIR/.libs/example_plugin', oC, SHLIBPREFIX='')
+ env.SharedLibrary('#$BINDIR/.libs/example_plugin_cpp', oCPP, SHLIBPREFIX='')
)
testExe = env.Program('#$BINDIR/test-plugin', ['plugin/plugin_main.c'] + core)
env.Depends(testExe, testplugin)
return testExe
#-- it depentds (at the moment) on a specific isolated test-plugin,
# testExe = env.Program('#$BINDIR/test-plugin', ['plugin/plugin_main.c'] + core)
# env.Depends(testExe, testplugin)
# return testExe
# 10/2008 example_plugin moved to backend directory.
# ...we should try to find some convention here
return testplugin
#-- it depends (at the moment) on a specific isolated test-plugin,
# which is not integrated in the "normal procedure" for building Plugins
# (which is not yet implemented as of 8/07)
# TODO: handle this case automatically
@ -71,7 +77,7 @@ specials = ['plugin','library','backend']
artifacts['testsuite'] = ts = ( [ testExecutable(env, dir) for dir in moduledirs if not dir in specials]
+ treatPluginTestcase(env)
# + treatPluginTestcase(env)
+ testCollection(env, 'library')
+ testCollection(env, 'backend')
)

View file

@ -83,6 +83,36 @@ TEST ("lookup")
}
TEST ("change_value")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
REQUIRE (argv[4]);
lumiera_config_init ("./");
const char* value;
if (!lumiera_config_set (argv[2], argv[3]))
printf ("failure setting first time '%s%s': %s\n", argv[2], argv[3], lumiera_error ());
if (lumiera_config_get (argv[2], &value))
printf ("%s\n", value);
else
printf ("failure retrieving '%s': %s\n", argv[2], lumiera_error ());
if (!lumiera_config_set (argv[2], argv[4]))
printf ("failure setting second time '%s%s': %s\n", argv[2], argv[4], lumiera_error ());
if (lumiera_config_get (argv[2], &value))
printf ("%s\n", value);
else
printf ("failure retrieving '%s': %s\n", argv[2], lumiera_error ());
lumiera_config_destroy ();
}
TEST ("basic_set_get")
{
REQUIRE (argv[2]);
@ -258,6 +288,7 @@ TEST ("configitem_simple_ctor_dtor")
lumiera_config_destroy ();
}
TEST ("configitem_simple_content_check")
{
REQUIRE (argv[2]);
@ -287,4 +318,95 @@ TEST ("configitem_simple_content_check")
lumiera_config_destroy ();
}
TEST ("wordlist_get_nth")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
REQUIRE (argv[4]);
lumiera_config_init ("./");
if (!lumiera_config_wordlist_set (argv[2], &argv[3]))
printf ("failed setting word '%s=%s': %s\n", argv[2], argv[3], lumiera_error ());
const char* word = lumiera_config_wordlist_get_nth (argv[2], atoi (argv[4]));
printf ("'%s'\n", word?word:"NULL");
lumiera_config_destroy ();
}
TEST ("wordlist_find")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
REQUIRE (argv[4]);
lumiera_config_init ("./");
if (!lumiera_config_wordlist_set (argv[2], &argv[3]))
printf ("failed setting word '%s=%s': %s\n", argv[2], argv[3], lumiera_error ());
int n = lumiera_config_wordlist_find (argv[2], argv[4]);
printf ("'%d'\n", n);
lumiera_config_destroy ();
}
TEST ("wordlist_replace")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
REQUIRE (argv[4]);
REQUIRE (argv[5]);
REQUIRE (argv[6]);
lumiera_config_init ("./");
if (!lumiera_config_wordlist_set (argv[2], &argv[3]))
printf ("failed setting word '%s=%s': %s\n", argv[2], argv[3], lumiera_error ());
const char* wordlist = lumiera_config_wordlist_replace (argv[2], argv[4], *argv[5]?argv[5]:NULL, *argv[6]?argv[6]:NULL);
if (wordlist)
printf ("'%s'\n", wordlist);
else
printf ("%s\n", lumiera_error ());
lumiera_config_destroy ();
}
TEST ("wordlist_add")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
REQUIRE (argv[4]);
REQUIRE (argv[5]);
lumiera_config_init ("./");
if (!lumiera_config_wordlist_set (argv[2], &argv[3]))
printf ("failed setting word '%s=%s': %s\n", argv[2], argv[3], lumiera_error ());
const char* wordlist = lumiera_config_wordlist_add (argv[2], argv[4]);
if (wordlist)
printf ("'%s'\n", wordlist);
else
printf ("%s\n", lumiera_error ());
wordlist = lumiera_config_wordlist_add (argv[2], argv[5]);
if (wordlist)
printf ("'%s'\n", wordlist);
else
printf ("%s\n", lumiera_error ());
lumiera_config_destroy ();
}
TESTS_END

View file

@ -0,0 +1,452 @@
/*
test-interfaces.c - test interfaces declaration and implementation
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "backend/interface.h"
#include "backend/interfaceregistry.h"
#include "backend/interfacedescriptor.h"
#include "tests/test.h"
/*
define 2 example interfaces
*/
LUMIERA_INTERFACE_DECLARE (lumieraorg_testexample_one, 0,
LUMIERA_INTERFACE_SLOT (void, foo1, (const char*)),
LUMIERA_INTERFACE_SLOT (void, bar1, (const char*)),
);
LUMIERA_INTERFACE_DECLARE (lumieraorg_testexample_two, 0,
LUMIERA_INTERFACE_SLOT (void, foo2, (const char*)),
LUMIERA_INTERFACE_SLOT (void, bar2, (const char*)),
);
LUMIERA_INTERFACE_DECLARE (lumieraorg_testexample_void, 0
);
/*
now the functions we want to bind to them
*/
void
testfunc (const char* message)
{
printf ("Called as '%s'\n", message);
}
LumieraInterface
testacquire (LumieraInterface self)
{
printf ("Acquire %s_%d_%s\n", self->interface, self->version, self->name);
return self;
}
void
testrelease (LumieraInterface self)
{
printf ("Release %s_%d_%s\n", self->interface, self->version, self->name);
}
/*
implementation of some example interfaces
*/
LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0,
lumieraorg_tests_descriptor,
/*self reference, yay*/
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire,
testrelease,
LUMIERA_INTERFACE_INLINE (name, "\073\003\054\127\344\046\324\321\221\262\232\026\376\123\125\243",
const char*, (LumieraInterface iface),
{return "Lumiera Test suite examples";}
),
LUMIERA_INTERFACE_INLINE (version, "\271\330\345\066\304\217\211\065\157\120\031\365\304\363\364\074",
const char*, (LumieraInterface iface),
{return "No Version";}
),
LUMIERA_INTERFACE_INLINE (author, "\367\160\342\065\147\007\237\371\141\335\371\131\025\030\257\232",
const char*, (LumieraInterface iface),
{return "Christian Thaeter <ct@pipapo.org>";}
),
LUMIERA_INTERFACE_INLINE (copyright, "\163\106\344\014\251\125\111\252\236\322\174\120\335\225\333\245",
const char*, (LumieraInterface iface),
{
return
"Copyright (C) Lumiera.org\n"
" 2008 Christian Thaeter <ct@pipapo.org>";
}
),
LUMIERA_INTERFACE_INLINE (license, "\343\031\207\122\225\217\014\163\015\023\243\101\165\377\222\350",
const char*, (LumieraInterface iface),
{
return
"This program is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation; either version 2 of the License, or\n"
"(at your option) any later version.\n"
"\n"
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA";
}
)
);
LUMIERA_EXPORT (interfaces_defined_here,
LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_one, 0,
lumieraorg_first_test,
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire,
testrelease,
LUMIERA_INTERFACE_MAP (foo1, "\214\310\136\372\003\344\163\377\075\100\070\200\375\221\227\324",
testfunc),
LUMIERA_INTERFACE_MAP (bar1, "\262\253\067\211\157\052\212\140\114\334\231\250\340\075\214\030",
testfunc)
),
LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_two, 0,
lumieraorg_second_test,
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire,
testrelease,
LUMIERA_INTERFACE_MAP (foo2, "\110\152\002\271\363\052\324\272\373\045\132\270\277\000\271\217",
testfunc),
LUMIERA_INTERFACE_MAP (bar2, "\376\042\027\336\355\113\132\233\350\312\170\077\377\370\356\167",
testfunc)
)
);
/*
Now we rig a cross dependency test
we have 4 instances, the respective acquire/release operations set following up:
one depends on two and three
two depends on one and four
three depends on two and four
four depends on one, two three
These all are empty interfaces with no slots
*/
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) one_keeps_two;
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) one_keeps_three;
LumieraInterface
testacquire_one (LumieraInterface self)
{
TRACE (tests, "Acquire one %s_%d_%s", self->interface, self->version, self->name);
one_keeps_two = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_two);
one_keeps_three = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_three);
return self;
}
void
testrelease_one (LumieraInterface self)
{
TRACE (tests, "Release one %s_%d_%s", self->interface, self->version, self->name);
lumiera_interface_close ((LumieraInterface)one_keeps_two);
lumiera_interface_close ((LumieraInterface)one_keeps_three);
}
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) two_keeps_one;
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) two_keeps_four;
LumieraInterface
testacquire_two (LumieraInterface self)
{
TRACE (tests, "Acquire two %s_%d_%s", self->interface, self->version, self->name);
two_keeps_one = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_one);
two_keeps_four = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_four);
return self;
}
void
testrelease_two (LumieraInterface self)
{
TRACE (tests, "Release two %s_%d_%s", self->interface, self->version, self->name);
lumiera_interface_close ((LumieraInterface)two_keeps_one);
lumiera_interface_close ((LumieraInterface)two_keeps_four);
}
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) three_keeps_two;
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) three_keeps_four;
LumieraInterface
testacquire_three (LumieraInterface self)
{
TRACE (tests, "Acquire three %s_%d_%s", self->interface, self->version, self->name);
three_keeps_two = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_two);
three_keeps_four = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_four);
return self;
}
void
testrelease_three (LumieraInterface self)
{
TRACE (tests, "Release three %s_%d_%s", self->interface, self->version, self->name);
lumiera_interface_close ((LumieraInterface)three_keeps_two);
lumiera_interface_close ((LumieraInterface)three_keeps_four);
}
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) four_keeps_one;
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) four_keeps_two;
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) four_keeps_three;
LumieraInterface
testacquire_four (LumieraInterface self)
{
TRACE (tests, "Acquire four %s_%d_%s", self->interface, self->version, self->name);
four_keeps_one = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_one);
four_keeps_two = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_two);
four_keeps_three = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_three);
return self;
}
void
testrelease_four (LumieraInterface self)
{
TRACE (tests, "Release four %s_%d_%s", self->interface, self->version, self->name);
lumiera_interface_close ((LumieraInterface)four_keeps_one);
lumiera_interface_close ((LumieraInterface)four_keeps_two);
lumiera_interface_close ((LumieraInterface)four_keeps_three);
}
LUMIERA_EXPORT (dependencytests,
LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_void, 0,
lumieraorg_dependencytest_one,
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire_one,
testrelease_one
),
LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_void, 0,
lumieraorg_dependencytest_two,
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire_two,
testrelease_two
),
LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_void, 0,
lumieraorg_dependencytest_three,
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire_three,
testrelease_three
),
LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_void, 0,
lumieraorg_dependencytest_four,
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire_four,
testrelease_four
)
);
TESTS_BEGIN
TEST ("basic")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (interfaces_defined_here());
/* some ugly lowlevel handling tests */
LumieraInterface handle1 =
lumiera_interfaceregistry_interface_find ("lumieraorg_testexample_one", 0, "lumieraorg_first_test");
(LUMIERA_INTERFACE_CAST(lumieraorg_testexample_one, 0)handle1)->bar1 ("this is bar1");
LUMIERA_INTERFACE_TYPE(lumieraorg_testexample_two, 0)* handle2 = LUMIERA_INTERFACE_CAST(lumieraorg_testexample_two, 0)
lumiera_interfaceregistry_interface_find ("lumieraorg_testexample_two", 0, "lumieraorg_second_test");
handle2->foo2 ("this is foo2");
lumiera_interfaceregistry_bulkremove_interfaces (interfaces_defined_here());
lumiera_interfaceregistry_destroy ();
}
TEST ("open_close")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (interfaces_defined_here());
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_one, 0) handle =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_one, 0, 0, lumieraorg_first_test);
ENSURE (handle);
handle->bar1 ("this is bar1");
lumiera_interface_close ((LumieraInterface)handle);
lumiera_interfaceregistry_bulkremove_interfaces (interfaces_defined_here());
lumiera_interfaceregistry_destroy ();
}
TEST ("dependencies_one")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (dependencytests());
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_one);
ENSURE (handle);
TRACE (tests, "Sucessfully opened");
lumiera_interface_close ((LumieraInterface)handle);
lumiera_interfaceregistry_bulkremove_interfaces (dependencytests());
lumiera_interfaceregistry_destroy ();
}
TEST ("dependencies_two")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (dependencytests());
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_two);
ENSURE (handle);
TRACE (tests, "Sucessfully opened");
lumiera_interface_close ((LumieraInterface)handle);
lumiera_interfaceregistry_bulkremove_interfaces (dependencytests());
lumiera_interfaceregistry_destroy ();
}
TEST ("dependencies_three")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (dependencytests());
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_three);
ENSURE (handle);
TRACE (tests, "Sucessfully opened");
lumiera_interface_close ((LumieraInterface)handle);
lumiera_interfaceregistry_bulkremove_interfaces (dependencytests());
lumiera_interfaceregistry_destroy ();
}
TEST ("dependencies_four")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (dependencytests());
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_four);
ENSURE (handle);
TRACE (tests, "Sucessfully opened");
lumiera_interface_close ((LumieraInterface)handle);
lumiera_interfaceregistry_bulkremove_interfaces (dependencytests());
lumiera_interfaceregistry_destroy ();
}
TEST ("dependencies_all")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (dependencytests());
TRACE (tests, "OPEN one");
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle_one =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_one);
ENSURE (handle_one);
TRACE (tests, "OPEN three");
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle_three =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_three);
ENSURE (handle_three);
TRACE (tests, "OPEN two");
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle_two =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_two);
ENSURE (handle_two);
TRACE (tests, "OPEN four");
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle_four =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_four);
ENSURE (handle_four);
TRACE (tests, "Sucessfully OPENED");
TRACE (tests, "CLOSE four");
lumiera_interface_close ((LumieraInterface)handle_four);
TRACE (tests, "CLOSE two");
lumiera_interface_close ((LumieraInterface)handle_two);
TRACE (tests, "CLOSE three");
lumiera_interface_close ((LumieraInterface)handle_three);
TRACE (tests, "CLOSE one");
lumiera_interface_close ((LumieraInterface)handle_one);
lumiera_interfaceregistry_bulkremove_interfaces (dependencytests());
lumiera_interfaceregistry_destroy ();
}
TEST ("highlevel, plugin")
{
}
TESTS_END
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -0,0 +1,121 @@
/*
StreamTypeBasics(Test) - check the fundamentals of stream type information
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
#include "common/test/run.hpp"
#include "common/util.hpp"
#include "proc/control/stypemanager.hpp"
#include "teststreamtypes.hpp"
#include <iostream>
using std::cout;
using ::test::Test;
using util::isnil;
namespace lumiera {
namespace test_format {
using control::STypeManager;
typedef StreamType const& SType;
typedef StreamType::ImplFacade const& ImplType;
/*******************************************************************
* @test check the basic workings of the stream type handling.
* create some stream implementation data, build a
* StreamType::ImplFacade from this, and derive a prototype
* and a full StreamType based on this information.
*/
class StreamTypeBasics_test : public Test
{
virtual void
run (Arg arg)
{
ImplType iType = buildImplType ();
basicImplTypeProperties (iType);
SType type = extend2fullType (iType);
basicStreamTypeProperties (type, iType);
}
ImplType
buildImplType ()
{
STypeManager& typeManager = STypeManager::instance();
gavl_video_format_t rawType = test_createRawType();
ImplType iTy (typeManager.getImpl (GAVL, rawType));
UNIMPLEMENTED ("at least preliminary implementation of the MediaImplLib interface for lib GAVL");
TODO ("how to do a simple consistency check on the returned ImplFacade? can we re-create the GAVL frame type?");
ASSERT (GAVL==iTy.libraryID);
return iTy;
}
void
basicImplTypeProperties (ImplType refType)
{
ImplType iTy2 = test_createImplType ();
ASSERT (iTy2==refType);
ASSERT (refType==iTy2);
TODO ("add equality comparable concept to the ImplType class");
ASSERT (StreamType::VIDEO==refType.getKind());
UNIMPLEMENTED ("get a lib descriptor");
UNIMPLEMENTED ("check the lib of the type");
UNIMPLEMENTED ("compare two types");
}
SType
extend2fullType (ImplType iTy)
{
return STypeManager::instance().getType(iTy);
}
void
basicStreamTypeProperties (SType type, ImplType iTy)
{
ASSERT (type.implType);
ASSERT (iTy==(*type.implType)); /////////////TODO: really by ptr???
ASSERT (&iTy==type.implType); // actually using the same object (in the registry)
ASSERT (!isnil (type.prototype.id));
ASSERT (StreamType::VIDEO==type.prototype.kind);
ASSERT (StreamType::VIDEO==type.implType->getKind());
ASSERT (type.implType->canConvert(iTy)); // of course... they are actually the same
ASSERT (iTy.canConvert(type)); // because it's based on the same impl type
ASSERT (StreamType::RAW==type.intentionTag);
}
};
LAUNCHER (StreamTypeBasics_test, "unit common");
} // namespace test_format
} // namespace lumiera

View file

@ -0,0 +1,114 @@
/*
StreamTypeLifecycle(Test) - check lifecycle of the stream type registration
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
#include "common/test/run.hpp"
#include "common/util.hpp"
#include "proc/control/stypemanager.hpp"
#include "proc/mobject/session.hpp"
//#include "teststreamtypes.hpp"
#include <iostream>
using std::cout;
namespace lumiera {
namespace test_format {
using mobject::Session;
using control::STypeManager;
using control::ON_STREAMTYPES_RESET;
//////////TODO define a dummy-type-info here
//////////TODO
void
setup_basicDummyTypeInfo ()
{
UNIMPLEMENTED ("setup basic dummy-type-info");
}
namespace // enroll this basic setup to be triggered when the type system is reset
{
LifecycleHook _schedule_at_reset (ON_STREAMTYPES_RESET, &setup_basicDummyTypeInfo);
}
/*******************************************************************
* @test check the stream type registration lifecycle.
* Any internal or external component (plugin) can extend
* the Proc Layer's registry of media stream types.
* There is a basic pristine set of type information, which is
* restored automatically everytime the STypeManager is reset,
* which in turn happenes before loading a (new) Session.
*/
class StreamTypeLifecycle_test : public Test
{
virtual void
run (Arg arg)
{
check_pristineState ();
register_additional_TypeInfo ();
check_pristineState ();
}
/** @test this test defines a new (dummy) type info
* and schedules it for setop in the pristine state;
* check this info is actually present after resetting
* the stream type manager, while other additional info
* \em not scheduled in this manner is not present
* in this state
*/
void
check_pristineState ()
{
Session::current.reset();
TODO ("verify the test-dummy basic type info is present now...");
TODO ("verify the additional type info is *not* present");
}
/** @test use the stream type manager to register additional
* type info and verify it is used in type resolution.
*/
void
register_additional_TypeInfo ()
{
TODO ("verify the additional type info is *not* present");
STypeManager& typeManager = STypeManager::instance();
TODO ("use the registration facility to add additional type info");
TODO ("verify the additional type info to be present now...");
}
};
LAUNCHER (StreamTypeLifecycle_test, "unit common");
} // namespace test_format
} // namespace lumiera

View file

@ -0,0 +1,96 @@
/*
TESTSTREAMTYPES.hpp - create test (stub) stream type information
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LUMIERA_TEST_TESTSTREAMTYPES_H
#define LUMIERA_TEST_TESTSTREAMTYPES_H
//#include "common/util.hpp"
#include "common/streamtype.hpp"
#include "proc/control/stypemanager.hpp"
extern "C" {
#include <gavl/gavl.h>
}
namespace lumiera {
namespace test_format {
namespace { // constants used to parametrize tests
const int TEST_IMG_WIDTH = 40;
const int TEST_IMG_HEIGHT = 30;
const int TEST_FRAME_DUR = GAVL_TIME_SCALE / 25;
}
Symbol GAVL = "GAVL";
/** Helper: create an raw GAVL type descriptor
* usable for generating a Lumiera StreamType
*/
inline gavl_video_format_t
test_createRawType ()
{
gavl_video_format_t type;
type.pixelformat = GAVL_RGB_24;
type.interlace_mode = GAVL_INTERLACE_NONE;
type.framerate_mode = GAVL_FRAMERATE_CONSTANT;
type.chroma_placement = GAVL_CHROMA_PLACEMENT_DEFAULT;
type.image_width = TEST_IMG_WIDTH; // Width of the image in pixels
type.image_height = TEST_IMG_WIDTH; // Height of the image in pixels
type.frame_width = TEST_IMG_WIDTH; // Width of the frame buffer in pixels, might be larger than image_width
type.frame_height = TEST_IMG_WIDTH; // Height of the frame buffer in pixels, might be larger than image_height
type.pixel_width = 1; // Relative width of a pixel (pixel aspect ratio is pixel_width/pixel_height)
type.pixel_height = 1; // Relative height of a pixel (pixel aspect ratio is pixel_width/pixel_height)
type.frame_duration = TEST_FRAME_DUR; // Duration of a frame in timescale tics.
type.timescale = GAVL_TIME_SCALE; // Timescale in tics per second (is defined to be 1000000 as of 9/2008)
return type;
}
/** Helper: create an implementation frame
* and build the corresponding streamtype
*/
inline StreamType::ImplFacade const&
test_createImplType ()
{
gavl_video_format_t rawType = test_createRawType();
return control::STypeManager::instance().getImpl (GAVL, rawType);
}
} // namespace test_format
} // namespace lumiera
#endif

View file

@ -85,7 +85,46 @@ TEST ("nestedmutexsection")
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
}
TEST ("chainedmutexsection")
{
lumiera_mutex m;
lumiera_mutex_init (&m, "m_mutexsection", &NOBUG_FLAG(NOBUG_ON));
lumiera_mutex n;
lumiera_mutex_init (&n, "n_mutexsection", &NOBUG_FLAG(NOBUG_ON));
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
{
printf ("outer mutex locked section\n");
LUMIERA_MUTEX_SECTION_CHAIN (NOBUG_ON, &n)
{
printf ("inner but not outer mutex locked section\n");
}
}
lumiera_mutex_destroy (&n, &NOBUG_FLAG(NOBUG_ON));
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
}
TEST ("recursivemutexsection")
{
lumiera_mutex m;
lumiera_recmutex_init (&m, "m_mutexsection", &NOBUG_FLAG(NOBUG_ON));
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
{
printf ("mutex locked once\n");
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
{
printf ("mutex locked twice\n");
}
}
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
}
TEST ("rwlocksection")
{

View file

@ -1,3 +0,0 @@
working example code for Lumiera's plugin system
This directory contains example code which shows how to use specific features.
All examples will be build and run as part of the testsuite

View file

@ -1,37 +0,0 @@
# Copyright (C) Lumiera.org
# 2007, Christian Thaeter <ct@pipapo.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
examples_srcdir = $(top_srcdir)/tests/plugin
noinst_PROGRAMS += test-plugin
test_plugin_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Werror
test_plugin_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_plugin_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl
test_plugin_SOURCES = $(examples_srcdir)/plugin_main.c
noinst_HEADERS += $(examples_srcdir)/hello_interface.h
check_LTLIBRARIES += example_plugin.la example_plugin_cpp.la
example_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
example_plugin_la_SOURCES = $(examples_srcdir)/example_plugin.c
# the -rpath option is required, prolly a automake bug?
example_plugin_la_LDFLAGS = -avoid-version -module -rpath $(shell pwd)
example_plugin_cpp_la_CPPFLAGS = $(AM_CPPFLAGS) -Wall -Werror
example_plugin_cpp_la_SOURCES = $(examples_srcdir)/example_plugin.cpp
# the -rpath option is required, prolly a automake bug?
example_plugin_cpp_la_LDFLAGS = -avoid-version -module -rpath $(shell pwd)

View file

@ -1,6 +1,6 @@
format 40
"MObject" // ProcessingLayer::MObject
revision 31
revision 32
modified_by 5 "hiv"
// class settings
//class diagram settings
@ -1189,8 +1189,6 @@ ${inlines}
package_ref 128901 // Builder
package_ref 129029 // Controller
usecaseview 128261 "config examples"
//use case diagram settings
package_name_in_tab default show_context default auto_label_position default draw_all_relations default shadow default

View file

@ -1,6 +1,6 @@
format 40
"CommonLib" // CommonLib
revision 12
revision 13
modified_by 5 "hiv"
// class settings
//class diagram settings
@ -26,6 +26,132 @@ format 40
package_name_in_tab default show_context default show_opaque_action_definition default auto_label_position default write_flow_label_horizontally default draw_all_relations default shadow default
show_infonote default drawing_language default
classview 129285 "StreamType"
//class diagram settings
draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default
//collaboration diagram settings
show_full_operations_definition default show_hierarchical_rank default write_horizontally default drawing_language default package_name_in_tab default show_context default draw_all_relations default shadow default
//object diagram settings
write_horizontally default package_name_in_tab default show_context default auto_label_position default draw_all_relations default shadow default
//sequence diagram settings
show_full_operations_definition default write_horizontally default class_drawing_mode default drawing_language default draw_all_relations default shadow default
//state diagram settings
package_name_in_tab default show_context default auto_label_position default write_trans_label_horizontally default show_trans_definition default draw_all_relations default shadow default
show_activities default region_horizontally default drawing_language default
//class settings
//activity diagram settings
package_name_in_tab default show_context default show_opaque_action_definition default auto_label_position default write_flow_label_horizontally default draw_all_relations default shadow default
show_infonote default drawing_language default
classdiagram 132485 "Stream Type Framework"
draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default
size A4
end
class 144773 "StreamType"
visibility package
cpp_decl "${comment}${template}class ${name}${inherit}
{
${members} };
${inlines}
"
java_decl ""
idl_decl ""
explicit_switch_type ""
classrelation 158469 // <unidirectional association>
relation 154373 --->
a role_name "" multiplicity "" protected
cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
"
classrelation_ref 158469 // <unidirectional association>
b multiplicity "" parent class_ref 145285 // MediaKind
end
classrelation 158597 // <unidirectional association>
relation 154501 --->
a role_name "" multiplicity "" protected
cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
"
classrelation_ref 158597 // <unidirectional association>
b multiplicity "" parent class_ref 144901 // Prototype
end
classrelation 158725 // <unidirectional association>
relation 154629 --->
a role_name "" multiplicity "" protected
cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value};
"
classrelation_ref 158725 // <unidirectional association>
b multiplicity "" parent class_ref 145029 // ImplFacade
end
end
class 144901 "Prototype"
visibility package
cpp_decl "${comment}${template}class ${name}${inherit}
{
${members} };
${inlines}
"
java_decl ""
idl_decl ""
explicit_switch_type ""
end
class 145029 "ImplFacade"
visibility package
cpp_decl "${comment}${template}class ${name}${inherit}
{
${members} };
${inlines}
"
java_decl ""
idl_decl ""
explicit_switch_type ""
end
class 145157 "StreamTypeID"
visibility package
cpp_decl "${comment}${template}class ${name}${inherit}
{
${members} };
${inlines}
"
java_decl ""
idl_decl ""
explicit_switch_type ""
classrelation 158341 // <dependency>
relation 154245 -_->
a default
cpp default "Generated"
classrelation_ref 158341 // <dependency>
b multiplicity "" parent class_ref 144773 // StreamType
end
end
class 145285 "MediaKind"
visibility package stereotype "enum"
cpp_decl "${comment}enum ${name}
{
${items}
};
"
java_decl "${comment}${@}${visibility}${final}${abstract}enum ${name}${implements} {
${items};
${members}}
"
idl_decl "${comment}enum ${name} {
${items}};
"
explicit_switch_type ""
end
end
package_ref 131077 // ConfigQuery
classview 128773 "error"

View file

@ -1,6 +1,6 @@
format 38
"Controller" // ProcessingLayer::MObject::Controller
revision 5
format 40
"Control" // ProcessingLayer::Control
revision 6
modified_by 5 "hiv"
// class settings
//class diagram settings
@ -8,7 +8,7 @@ format 38
//use case diagram settings
package_name_in_tab default show_context default auto_label_position default draw_all_relations default shadow default
//sequence diagram settings
show_full_operations_definition default write_horizontally default drawing_language default draw_all_relations default shadow default
show_full_operations_definition default write_horizontally default class_drawing_mode default drawing_language default draw_all_relations default shadow default
//collaboration diagram settings
show_full_operations_definition default show_hierarchical_rank default write_horizontally default drawing_language default package_name_in_tab default show_context default draw_all_relations default shadow default
//object diagram settings
@ -34,7 +34,7 @@ format 38
//object diagram settings
write_horizontally default package_name_in_tab default show_context default auto_label_position default draw_all_relations default shadow default
//sequence diagram settings
show_full_operations_definition default write_horizontally default drawing_language default draw_all_relations default shadow default
show_full_operations_definition default write_horizontally default class_drawing_mode default drawing_language default draw_all_relations default shadow default
//state diagram settings
package_name_in_tab default show_context default auto_label_position default write_trans_label_horizontally default show_trans_definition default draw_all_relations default shadow default
show_activities default region_horizontally default drawing_language default
@ -172,7 +172,7 @@ ${inlines}
comment "Encapsulates the logic used to get a \"current render process\" in accordance to the currentyl applicable controller settings. The provided StateProxy serves to hold any mutalbe state used in the render process, so the rest of the render engine can be stateless."
operation 128389 "getStateProxy"
public return_type class_ref 132741 // StateProxy
public return_type class_ref 132741 // State
nparams 0
cpp_decl " ${comment}${friend}${static}${inline}${virtual}${type} ${name} ${(}${)}${const}${volatile} ${throw}${abstract};"
cpp_def "${comment}${inline}${type}
@ -186,5 +186,18 @@ ${class}::${name} ${(}${)}${const}${volatile} ${throw}${staticnl}
end
end
class 145413 "STypeManager"
visibility package
cpp_decl "${comment}${template}class ${name}${inherit}
{
${members} };
${inlines}
"
java_decl ""
idl_decl ""
explicit_switch_type ""
end
end
end

View file

@ -1,6 +1,6 @@
format 40
"ProcessingLayer" // ProcessingLayer
revision 22
revision 23
modified_by 5 "hiv"
// class settings
//class diagram settings
@ -28,6 +28,8 @@ format 40
package_ref 128133 // Asset
package_ref 129029 // Control
package_ref 128261 // MObject
package_ref 128389 // RenderEngine

View file

@ -1,6 +1,6 @@
format 40
"common" // design::codegen::common
revision 14
revision 15
modified_by 5 "hiv"
// class settings
//class diagram settings
@ -201,6 +201,46 @@ ${namespace_end}"
end
comment "unified representation of a time point, including conversion functions"
end
artifact 139653 "streamtype"
stereotype "source"
cpp_h "/*
${NAME}.hpp - ${description}
@{CopyrightClaim}@{GPLHeader}
*/
#ifndef ${NAMESPACE}_${NAME}_H
#define ${NAMESPACE}_${NAME}_H
${includes}
${declarations}
${namespace_start}
${definition}
${namespace_end}
#endif
"
cpp_src "/*
${Name} - ${description}
@{CopyrightClaim}@{GPLHeader}
* *****************************************************/
${includes}
${namespace_start}
${members}
${namespace_end}"
associated_classes
class_ref 144773 // StreamType
class_ref 144901 // Prototype
class_ref 145029 // ImplFacade
end
end
end
package_ref 130821 // error

View file

@ -1,6 +1,6 @@
format 40
"proc" // design::codegen::proc
revision 7
revision 8
modified_by 5 "hiv"
// class settings
//class diagram settings
@ -150,7 +150,7 @@ ${namespace_start}
${members}
${namespace_end}"
associated_classes
class_ref 132741 // StateProxy
class_ref 132741 // State
end
comment "Key Interface representing a render process and encapsulating state"
end
@ -236,6 +236,8 @@ ${namespace_end}"
package_ref 130053 // asset
package_ref 130693 // control
package_ref 130181 // mobject
package_ref 130309 // engine

View file

@ -1,6 +1,6 @@
format 40
"mobject" // design::codegen::proc::mobject
revision 8
revision 9
modified_by 5 "hiv"
// class settings
//class diagram settings
@ -394,6 +394,4 @@ ${namespace_end}"
package_ref 130437 // session
package_ref 130565 // builder
package_ref 130693 // controller
end

View file

@ -1,6 +1,6 @@
format 40
"controller" // design::codegen::proc::mobject::controller
revision 6
"control" // design::codegen::proc::control
revision 7
modified_by 5 "hiv"
// class settings
//class diagram settings
@ -27,13 +27,13 @@ format 40
show_infonote default drawing_language default
stereotype "src"
cpp_h_dir "proc/mobject/controller"
cpp_src_dir "proc/mobject/controller"
cpp_namespace "mobject::controller"
cpp_h_dir "proc/control"
cpp_src_dir "proc/control"
cpp_namespace "control"
comment "sourcecode package
The Processing and Render Controller,
located within the MObject Subsystem"
and the Proc-Layer dispatcher"
deploymentview 129157 "gen"
//deployment diagram settings
package_name_in_tab default show_context default write_horizontally default auto_label_position default draw_all_relations default shadow default
@ -116,5 +116,43 @@ ${namespace_end}"
end
comment "renderengine state manager"
end
artifact 139781 "stypemanager"
stereotype "source"
cpp_h "/*
${NAME}.hpp - ${description}
@{CopyrightClaim}@{GPLHeader}
*/
#ifndef ${NAMESPACE}_${NAME}_H
#define ${NAMESPACE}_${NAME}_H
${includes}
${declarations}
${namespace_start}
${definition}
${namespace_end}
#endif
"
cpp_src "/*
${Name} - ${description}
@{CopyrightClaim}@{GPLHeader}
* *****************************************************/
${includes}
${namespace_start}
${members}
${namespace_end}"
associated_classes
class_ref 145413 // STypeManager
end
end
end
end

View file

@ -1,6 +1,6 @@
format 40
"ConfigQuery" // CommonLib::ConfigQuery
revision 1
revision 2
modified_by 5 "hiv"
// class settings
//class diagram settings
@ -239,7 +239,7 @@ ${inlines}
classrelation 150405 // <dependency>
relation 147717 -_->
a default
cpp default "Generated"
cpp default "#include in header"
classrelation_ref 150405 // <dependency>
b multiplicity "" parent class_ref 140805 // TypeHandler
end
@ -390,7 +390,7 @@ ${inlines}
classrelation 150533 // <dependency>
relation 147845 -_->
a default
cpp default "Generated"
cpp default "#include in header"
classrelation_ref 150533 // <dependency>
b multiplicity "" parent class_ref 140549 // ConfigRules
end

View file

@ -0,0 +1,49 @@
format 40
classcanvas 128005 class_ref 144773 // StreamType
draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default
xyz 188 72 2000
end
classcanvas 128133 class_ref 144901 // Prototype
draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default
xyz 261 208 2000
end
classcanvas 128261 class_ref 145029 // ImplFacade
draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default
xyz 261 271 2000
end
classcanvas 128389 class_ref 145157 // StreamTypeID
draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default
xyz 38 72 2000
end
classcanvas 128645 class_ref 145285 // MediaKind
draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default
xyz 263 132 2000
end
classcanvas 129541 class_ref 145413 // STypeManager
draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default
xyz 40 256 2000
end
relationcanvas 128517 relation_ref 154245 // <dependency>
from ref 128389 z 1999 to ref 128005
no_role_a no_role_b
no_multiplicity_a no_multiplicity_b
relationcanvas 128773 relation_ref 154373 // <unidirectional association>
geometry VH
from ref 128005 z 1999 to point 223 162
line 128901 z 1999 to ref 128645
no_role_a no_role_b
no_multiplicity_a no_multiplicity_b
relationcanvas 129029 relation_ref 154501 // <unidirectional association>
geometry VH
from ref 128005 z 1999 to point 223 227
line 129157 z 1999 to ref 128133
no_role_a no_role_b
no_multiplicity_a no_multiplicity_b
relationcanvas 129285 relation_ref 154629 // <unidirectional association>
geometry VH
from ref 128005 z 1999 to point 223 290
line 129413 z 1999 to ref 128261
no_role_a no_role_b
no_multiplicity_a no_multiplicity_b
end

View file

@ -4,16 +4,21 @@ diagrams
407 690 100 4 2 0
collaborationdiagram_ref 132229 // Render Process
825 684 100 4 0 0
active classdiagram_ref 132357 // StateAdapter composition
classdiagram_ref 132357 // StateAdapter composition
414 658 100 4 0 0
active classdiagram_ref 132485 // Stream Type Framework
463 594 100 4 0 0
end
show_stereotypes
selected
package_ref 129 // lumiera
package_ref 129 // lumiera
open
class_ref 132741 // State
deploymentview_ref 128261 // gen
deploymentview_ref 129157 // gen
package_ref 129029 // Controller
package_ref 130181 // mobject
classview_ref 128389 // Controller Workings
class_ref 132741 // State
class_ref 131717 // ProcNode
class_ref 142469 // StateProxy
class_ref 142597 // StateAdapter
@ -28,11 +33,7 @@ package_ref 129029 // Controller
class_ref 144005 // BuffTable
class_ref 144261 // Invocation
usecaseview_ref 128005 // Renderengine Use
class_ref 140677 // QueryHandler
class_ref 140805 // TypeHandler
class_ref 140933 // ResolverBase
class_ref 141189 // QueryHandlerImpl
usecaseview_ref 128389 // query use
classview_ref 129285 // StreamType
classview_ref 128773 // error
class_ref 140165 // Visitable
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -635,6 +635,27 @@ ColorPalette
SiteUrl</pre>
</div>
<div title="ArchitectureOverview" modifier="Ichthyostega" modified="200810151608" created="200810151553" changecount="7">
<pre>This page intends to capture the lage picture regarding Lumiera's Architecture. This may be a moving target...
[img[Overview of Lumiera Architecture|draw/Lumi.Architecture-1.png][http://www.lumiera.org/gitweb?p=LUMIERA;f=doc/devel/draw/Lumi.Architecture-1.svg;hb=HEAD]]
//this drawing is maintained as SVG in GIT//
~~(click on the above image...)~~
!Description
* the Application has three Layers: [[Backend|backend.html]], [[Proc-Layer|renderengine.html]] and GUI
* the Application shall be completely functional without GUI (&quot;headless&quot;, script-driven)
* all IO, media data fetching, processing and bookkeeping falls within the realm of the Backend
* all media object manipulation, deciding and configuration is the Proc Layer's job
* extensible by plugins on all levels, highly configurable, but not totally componentized (micro kernel) architecture
* strong separation between high-level and low-level areas of the Application
* the user/GUI manipulates a [[high-level model|renderengine.html#HighLevelModel]] whereas rendering is based on a corresponding [[low-level model|renderengine.html#OverviewRenderEngine]]
* stored Session (state) is comprised of high-level model, a collection of [[Assets|renderengine.html#Asset]] and accompaning configuration
* (possibly) several storage backends, abstracted out by a common interface
</pre>
</div>
<div title="AutoTools" modifier="Ichthyostega" modified="200805200610" created="200805200609" changecount="3">
<pre>* autotools 1.10 (as of 5/2008) &amp;dash; Question: other versions usable too?
* the usual procedure, in short
@ -802,14 +823,12 @@ for __Running__</pre>
<pre>LumieraWiki
ShortCuts</pre>
</div>
<div title="DesignDocumentation" modifier="Ichthyostega" modified="200810050447" created="200706181207" tags="process policy" changecount="7">
<div title="DesignDocumentation" modifier="CehTeh" modified="200707030409" created="200706181207" tags="process policy" changecount="6">
<pre>* There is a [[Manifest]] explaining the vision of the Lumiera project
* The foundation how we work together is defined in LumieraDesignProcess
* There is a description how the git repository is set up in RepositorySetup
* we decided to write code in GNU style, with no tabs (use spaces)
!basic decisions
* TimeHandling</pre>
</pre>
</div>
<div title="FullScreenPlugin" modifier="CehTeh" modified="200706110313" created="200607241016" tags="systemConfig lewcidExtension" server.type="file" server.host="file:///home/ct/.homepage/home.html" server.page.revision="200706110313">
<pre>/***
@ -954,9 +973,11 @@ git push git://git.pipapo.org/lumiera/mob
lumiera/mob is an anonymous account at pipapo.org where everyone can commit changes. </pre>
</div>
<div title="IRC-Transcripts" modifier="Ichthyostega" modified="200807072122" created="200708120209" tags="discuss irclog" changecount="11">
<div title="IRC-Transcripts" modifier="Ichthyostega" modified="200810151611" created="200708120209" tags="discuss irclog" changecount="12">
<pre>We keep a protocol or short summary of each important discussion. The summaries of the monthly developer meetings are posted to the Mailinglist and can be found on pipapo.org too
* [[10-08 developer meeting 10.Oct.2008|IRC_2008-10-10]]
* [[07-08 developer meeting 6.Jul.2008|IRC_2008-07-06]]
* [[06-08 developer meeting 5.Jun.2008|IRC_2008-06-05]]
* [[05-08 developer meeting 8.May.2008|IRC_2008-05-08]]
* [[04-08 developer meeting 3.Apr.2008|IRC_2008-04-03]]
@ -968,12 +989,12 @@ lumiera/mob is an anonymous account at pipapo.org where everyone can commit chan
* [[buffer allocation for render nodes (6/08)|IRC_log_BufferAllocation_2008-06]]
</pre>
</div>
<div title="IRC_2007-08-10" modifier="Ichthyostega" created="200802021815" tags="irclog" changecount="1">
<div title="IRC_2007-08-10" modifier="Ichthyostega" modified="200810140236" created="200802021815" tags="irclog" changecount="2">
<pre>!10/11 aug 2007
* maybe let the render graph builder generate a meta language which then is ''jit compiled'' for each configuration
* using smart pointers and factories for objects ''and avoid unprotected use of {{{new}}} and {{{delete}}}'', if this wont work because of cycles, we might investigate specialized garbage collectors for specific cases.
* format for frames would be likely ffmpeg or such first, finally we see what suits best. We have to provide coverter nodes to convert frame formats for accessing diffrent libraries anyway (ffmpeg, v4l, gstreamer, ...)
* we need a pool of worker threads and associated api's
* format for frames would be likely ffmpeg or such first, finally we see what suits best. We have to provide coverter nodes to convert frame formats for accessing different libraries anyway (ffmpeg, v4l, gstreamer, ...)
* we need a pool of worker threads and associated ~APIs
* accessing frames has a time (get until..), ''unique frame identifier'' (see below), policies (what to do when out of time, quality required,..) and hints (recursive dependency, must cache, playback speed and direction, ...)
* for each sequence (configuration) each node has a number (monotonic incrementing), a generation counter (increment on each parameter change), a propagation sum (from parent nodes)
* frames are identified by their time(frame number) and node number plus generation number and propagation sum. This allows easily to find out when a frame has to be rerendered
@ -981,20 +1002,20 @@ lumiera/mob is an anonymous account at pipapo.org where everyone can commit chan
** viewer is just a decoder where a display window attaches
** one can have multiple of such display windows
** tracks, effects, (things which are nodes in the render graph) can add gui components to the viewer, like masking tools, panning, overlay and other compositor things.
** in the render graph we have ''attachement points'' i.e. ~ExitNode-instances. Display and other output can only be pulled from such ~ExitNodes. Changing just the display or attaching it to another ~ExitNode doesn't count as change of the render graph, while reordering or reconfiguring the ~ExitNodes themselfes of course //is// a reconfig.
** in the render graph we have ''attachment points'' i.e. ~ExitNode-instances. Display and other output can only be pulled from such ~ExitNodes. Changing just the display or attaching it to another ~ExitNode doesn't count as change of the render graph, while reordering or reconfiguring the ~ExitNodes themselves of course //is// a reconfiguration.
* tracks are just containers for other nodes
** they serve a gui representation (timeline, patchbay, viewer)
** they serve a GUI representation (timeline, patchbay, viewer)
** they do the mixing of contained things
** can be recursive, the gui represents basically a tree
** we need some 'wireing' abstraction for the gui to make it a real graph
** can be recursive, the GUI represents basically a tree
** we need some 'wiring' abstraction for the GUI to make it a real graph
* rendering frames, context between frames
** the proc layer ''only queries frames'' (by identifier and timeout) the backend tries to serve the best it can do (from cache or let them render)
** each render job carries some ''quality limit'' (as S/N ratio) when previewing or scratching through the project this is used to generate reasonable quality previews
** individual processing nodes can use additional state for their processings...
*** the node objects themselfs should stay stateles, i.e. they shouldn't store state internally.
** individual processing nodes can use additional state for their calculations...
*** the node objects themselves should stay stateless, i.e. they shouldn't store state internally.
*** they can use special ''context frames'', which are provided and managed by the backend (as opaque data blocks).
*** they can depend on previous state, i.e request from the backend a previous context frame, the same way as they can request previous media frames from the bakend, but there is no guarantee that the backend will satisfy this request.
* on the question who decides what to do after a cache miss, we tend to put the decision into the render node (because this seems to be the simpler aproach), but still have to work out the details.
* on the question who decides what to do after a cache miss, we tend to put the decision into the render node (because this seems to be the simpler approach), but still have to work out the details.
</pre>
</div>
<div title="IRC_2008-02-01" modifier="Ichthyostega" modified="200802031846" created="200802021821" tags="irclog" changecount="28">
@ -1673,6 +1694,272 @@ While in this discussion, several aspects of the cooperation of GUI and Proc lay
Next meeting: ''Thursday 3.July 2008 16:30 UTC''
</pre>
</div>
<div title="IRC_2008-07-06" modifier="Ichthyostega" created="200810151616" tags="irclog excludeMissing" changecount="1">
<pre>! 6.July 2008 on #lumiera
__Participants__
* ichthyo
* cehteh
* jilt
* dmj726
* Teld
* _nasa_
* alcarinque_
* MNO
* Wescotte
* weatherhead
//Protocol written by Teld//
!Boilerplate
!!Organization of this meeting
* dmj726 intends to write the protocol
* ichtyo is chairman
* there is no agenda, so this is a freeform meeting
!!Leftovers from last meeting
//There are no leftovers//
!Introduction of Lumiera
Because there are quite some new participants, an introduction of the project Lumiera is given
There are 3 core devs:
* cehteh: backend serving data (from filesystem and so on), manages threads, using C, Posix System programming, maintains autotools and git
* ichthyo: proc layer, render graph, in the middle, C++, he maintains scons
* joelholdsworth: GUI in C++/Gtkm
Other people involved:
* rcbarnes: ui designer and HCI expert
* raffa: web content
* Simav: gives a hand when and where he can
* Teld: web infrastructure
The foundations of the design are already done but a lot of detail needs to be worked out. cehteh and ichtyo provide a non exhaustive list.
cehteh:
* improvement of the testsuite (simple Bash)
* start of a worker thread manager (Posix knowledge required)
* start of the scheduler (some Posix, good C coding)
* runtime profiler (little but advanced Posix realtime programming job)
* review of code and documentation
* system administration
* setup of a build/test environment on the server
* setup and maintain postfix/dovecot by a mail administrator
ichtyo:
* asset management (keeping track of all media files, captures, clips, scenes)
* session loading saving and the issues of compound documents
* session structure related issues to be able to Import/Export/Connect via e.g. OSC (Open Sound Control) or JACK
* flesh out the more high level &quot;edit operations&quot; and the interface to UNDO
* Prolog integration after the first integration round has been reached. The Prolog interpreter will do some of the more advanced configuration (example: if effect XYZ is used, then deinterlace beforehand).
* integration with some sort of production support software (like Celtx)
cehteh emphasizes that Lumiera is an open project, so anybody can jump in where he sees fit as long as he communicates and acknowledges with the persons involved. ichtyo points out that the plugin structure is very important: anything that is not legally completely clean (proprietary), should be factored out into a sister project and be loaded as plugin.
!Issues and questions that come up
!!handling of config errors.
When the configuration has a syntax error, in 90% of the cases there will be no possibility to do anything sane. Therefore, the config system will be built to log a warning and the user code does not need to care. The user just gets an alert and the application continues to work.
!!scripting language.
There will be a scripting interface. ichtyo does not want scripts everywhere, only at well defined interfaces. That implies also that scripts cannot just do anything, only that what is permitted in a controlled way. The meeting agrees on that. cehteh wants one default language and proposes Lua: light, simple.
Other members suggestions: Python, Ruby, Scheme. However, Python and Ruby are very slow. Scheme has many variants.
!!editing on small devices (eeePC)
Problem: video editors GUIs are some of the most elaborate and complicated GUIs. However, basic functions consist of only a few buttons. Proxy editing could be a solution. It is decided that it is not a primary goal now. First the basics have to be implemented.
!!uWiki.
uWiki is the glue between a markup driver (Asciidoc) and revision control (git). Haserl with Bash is used now. Haserl appears to have problems with conditional includes. Its limits have been reached while prototyping. Lua could very well be a valid replacement. It will be investigated. PHP is rejected because it is not stable and suffers from serious security problems.
!!'musical' timeline in bars and beats
The questions of syncing and linking things together are already on the core agenda: the so-called placement concept. Discussion is still going on, especially with the GUI developer joelholdsworth. See for detailed information: http://www.pipapo.org/pipawiki/Lumiera/DesignProcess/ProcPlacementMetaphor
!Next meeting
The next meeting will be held ''Thursday, 7 August 19:00 UTC''
</pre>
</div>
<div title="IRC_2008-10-10" modifier="Ichthyostega" modified="200810151623" created="200810151617" tags="irclog excludeMissing" changecount="6">
<pre>!Oct 10, 2008 on #lumiera
19:00 - 23:15 UTC
__Participants__
* cehteh
* ichthyo
* joelholdsworth
* alcarinque
* ~KenSentMe
* Plouj
* raffa
* thorwil
* Victor_Sigma
* wildhostile
//Protocol written by Ichthyo//
!!!organisational
Not much of a fixed agenda this time.
Agreement to start with the Logo discussion, as this is of general interest, followed by the design drafts and similar dev topics.
!The Lumiera Logo
Summary of the situation: discussion regarding a logo for Lumiera is going on sporadically since quite some time. Several people from the community have made proposals. Also, there was discussion about the criteria a logo would have to fulfil. Especially the core devs raised the bar and required quite some professional level of design. On the contrary, several members of the community were concerned that such a demanding attitude will hinder creativity in a domain which is far off from coding. Moreover, many people complained they are really excited about Lumiera and strongly want to participate in some manner, but find it very difficult in the current phase of the project to give any valuable contribution.
This summer, one of the proposals by [[Leandro Ribeiro|http://farm4.static.flickr.com/3060/2927333034_ac94be80ea_b.jpg]] gained some popularity and especially was embraced by two of the core devs, while the GUI core dev wasn't convinced and [[explained|http://www.pipapo.org/pipawiki/JoelHoldsworth/LogoThoughts]] his reservation. Prior to this meeting some people joined a brainstorming session and came up with [[another design|http://www.pipapo.org/pipawiki/Lumiera/Logos?action=AttachFile&amp;do=get&amp;target=combo.png]] compiled of several proposals, which could meet the acceptance of the core devs. At the same time, Raffa made an argument for conducting a public contest, similar to the one which gave us the name of Lumiera. The situation for Lumiera is somewhat special. Usually, the community builds when the product is already minimally usable; we can't have users for now, but we have a lot of prospective users.
Thus, while basically it would be possible for the core devs to shorten the process by just picking a design which is acceptable for all, maybe after augmenting it a little, several of the arguments articulated this far are in favour of a more formal decision by a contest:
* it would allow for a lot of people to really participate
* it could help to shape a general (graphic) style for Lumiera
* it could underpin the fact Lumiera indeed is a collaborative effort
* it doesn't mean additional work for the core devs on the whole
* it helps spreading the word
Then, there is some discussion about the requirements. The core devs are concerned to keep up some quality level, because there is the possibility for the community to embrace a design, but when Lumiera enters the area it is intended to do, the standards of comparison will be different. The GIMP logo can be quoted as a negative example here.
!!Conclusion
There will be a Lumiera Logo contest.
* we should further discuss requirements on the Mailinglist until the end of the next week
* the ''deadline for submissions'' will be the next meeting (Nov 12 2008)
* then, after a pre-selection phase, the vote shall be conducted prior to the December meeting.
Some minimal technical requirements will be enforced:
* the basic sign fits a compact rather quadratic bounding box (like 4:3)
* easy to print on various media (on posters, t-shirts, ..)
* basically a shape, using only a small number of solid colours (web safe)
* should work on different backgrounds, esp. not requiring white background
* the design should scale from microscopic size (favicon) up to big posters
* vector graphic source is mandatory
Besides, we give some artistic guidelines
* it should be recognisable
* it should contain something like a sign, not just &quot;Lumiera&quot; in a fancy font
* it should not rely on transparencies, gradients and subtle shades,
* it should be viable, possibly work well in different presentation styles, able to be simplified as well as graphically augmented
Raffa volunteers to help organizing the contest and the voting.
----
!Recurring Topics: design proposals
Discussion of open [[design process|http://www.pipapo.org/pipawiki/Lumiera/DesignProcess]] drafts.
!!Mistakes to avoid
[http://www.pipapo.org/pipawiki/Lumiera/DesignProcess/MistakestoAvoid Mistakes to avoid in the Lumiera Design]
We are carrying this one along since quite some time and we'd like to get rid of it, either by reworking it or by dropping it as-is. Because it contains a mixture of things
* we fully agree to 80% of the statements made there, but we think those statements are so very basic and self-evident as to be considered off-topic here. We are aware of the recurring problems with open source video editing. That's why we are here.
* the proposal draws conclusions on two technically substantial points, at which we don't agree. And it fails to provide sufficient (technically sound) arguments to prove these statements.
While it is certainly //desirable// to be cross-platform as much as possible and especially ''target Microsoft Windows'', we don't see much possibilities with today's mainstream technology to build an application which is as technologically demanding as a video editor is. We would end up developing two or even three sister applications, or we are forced to sacrifice performance for portability. When put up to face such options, we have a clear preference to concentrate on a really free and open platform.
While it is certainly //desirable// to make the application as robust as possible, we don't see how ''using multiple separate processes'' could help us with this goal //without creating major scalability or performance problems// due to the use of shared memory. And, yet more important: we don't share the basic assumption made in the proposal, namely that video processing is inherently dangerous. We think the basic algorithms involved are sufficiently well-known and understandable to implement them in a sound manner.
__Conclusion__: drop it
!!!!on the question of separate processes
The only practical solution would be to separate the GUI. Separating backend and proc-layer doesn't make much sense, technically speaking. We re-considered this question. Joelholdsworth (GUI) and Ichthyo (Proc-layer)prefer running the GUI in-process and to avoid the additional hassle with shared memory. Cehteh (backend) doesn't care for know and would like to re-discuss it as an option later on. This is somewhat similar to the possibility of running Lumiera distributed over the network, which is a goal, but not an immediate one.
!!Tag Clouds
[http://www.pipapo.org/pipawiki/Lumiera/DesignProcess/TagCloudsOnResources Tag clouds on resources]
Tags are considered very important. Meanwhile, we have a much more advanced proposal, which superseeds this one: [http://www.pipapo.org/pipawiki/Lumiera/DesignProcess/DelectusShotEvaluator &quot;Delectus&quot;]
__Conclusion__: drop it
!!Overview of Lumiera Architecture
[http://www.pipapo.org/pipawiki/Lumiera/DesignProcess/ArchitectureOverview Architecture Overview]
The purpose of this drawing to give an first impression what subsystem is where and what the names mean. Since discussed last time, Ichthyo re-arranged the plugins as requested and added some details for the backend. Joelholdsworth points out that it's OK for him to show the GUI just as a single block here (and of course the GUI has much more internal structure). Cehteh adds that maintaining this drawing surely is a moving target, so we better remove the rendered image and just retain the textual description and link to the source (SVG), which is in GIT.
__Conclusion__: accept it, change the image to a link
!!EDLs as Meta-Clips
[http://www.pipapo.org/pipawiki/Lumiera/DesignProcess/EDLsAreMetaClips EDLs are meta-clips]
This is just a high-level proposal, which doesn't go into technical details of implementing nested EDLs. It just poses the question &quot;do we want to treat nested EDLs as being meta-clip&quot; -- which we do.
__Conclusion__: accepted
!!The Builder
[http://www.pipapo.org/pipawiki/Lumiera/DesignProcess/ProcBuilder Builder in the Proc-Layer]
Similar to the previous one, this is a high-level proposal. It covers the fundamental approach Ichthyo takes within the Proc-Layer. Cehteh adds that he agrees to 98% and the remaining 2% are just matter of favour. Personally, he would have preferred one large graph which gets garbage collected (instead of the segmented graph)
__Conclusion__: accepted
!!High-level Model
[http://www.pipapo.org/pipawiki/Lumiera/DesignProcess/ProcHighLevelModel Overview of the High-level model within the Proc-Layer]
Cehteh queries if this shouldn't be better moved over to the documentation? He is fine with the contents, but it seems to be a bit voluminous for a design proposal. Ichthyo asks to leave it there just for now, as he feels it still needs review.
__Conclusion__: leave it for now, maybe retract it from the design proposals and file it as documentation?
!!Lua scripting language
[http://www.pipapo.org/pipawiki/Lumiera/DesignProcess/ScriptingLanguage use Lua as required scripting language]
All core devs agree with this decision. Joelholdsworth points out that he is fine with Lua, just he didn't want to write the GUI in it. Ichthyo adds that Lua is probably the best choice from today's mainstream scripting languages, because it is very lightweight. He further points out, that having Lua as //required// scripting language doesn't rule out using other popular languages (Python, Ruby) for scripting. Just they aren't required for running Lumiera. Cehteh will have a look at the details as soon as possible, but has currently other more urgent things in the queue. (Plouj shows interest to help here)
__Conclusion__: accepted
!!Time Handling
[http://www.pipapo.org/pipawiki/Lumiera/DesignProcess/time_handling time handling]
A long standing proposal; meanwhile we've decided to build on GAVL, which is now reflected in the text of this proposal too. Ichthyo points out he changed the rounding rule in this proposal from &quot;mathematical&quot; to &quot;floor (x+0.5)&quot;. Cehteh asks if we should use a thin library layer on top of gavl, to centralize all the time calculations. There seems to be agreement that this should actually be done //on demand.// Joelholdsworth sais sometimes he'd prefer to have a simple raw type to represent time, because it makes calculations much easier. Ichthyo adds that internally (within the layers, but not on interfaces) one could use a thin C++ wrapper with overloaded operators, which is default-convertible to gavl_time.
__Conclusion__: accepted
Note: the proposed rigid testsuite for time handling is necessary only when we introduce a wrapper...
!!Interface naming convention
See the design proposal [http://www.pipapo.org/pipawiki/Lumiera/DesignProcess/InterfaceNamespaces Interface Namespaces]. While working on the plugin loader, ''Cehteh'' and ''nasa'' did some brainstorming about a plugin naming scheme and how to get unique interface identifiers. The idea is to use a distinctive prefix, like a condensed organisation domain or email name, or a GPG fingerprint or even a UID, followed by the interface namespace hierarchy. These would be combined into a single identifier (valid C name). The intention is to get non-ambiguous names, yet avoiding the need of a central registry.
__Conclusion__: accepted
----
general Topics
!Config System
''cehteh'' landed the first version of this subsystem and asked for review and testing. Currently it's &quot;work with no progress&quot;, but it is basically usable (you can get values, you can set values by environment variables, but you can't persist). It should be augmented on demand, e.g. by adding the support for more value types (value types are a hint how to parse, and link the parsed value to a given C type).
!Use of Namespaces
Currently there is no clear uniform rule regarding namespaces use. ''Joelholdsworth'' places his code within lumiera::gui and below. He points out that external libs like Cairo, GTK, GLib will bring in their hierarchies and all of Lumiera should comply and put anything below a lumiera:: root. On the contrary, ''Ichthyo'' deliberately moved his implementation code away from the central lumiera:: interface hierarchy into shallow namespaces and avoids nesting. He argues that having all code below luimiera:: effectively makes this namespace global or forces it to be void of any function; rather he'd prefer to import every interface explicitly into the implementation namespace. ''Cehteh'' argues that having a global lumiera::, even if empty, would mark a general claim and stand for the uniformity of the project. Generally, there should be some correspondence between folders and namespaces.
No conclusion yet, to be discussed further.
!Interface Definition Language
In his work on the plugin loader, ''Cehteh'' created a first draft how to export an interface, and calls for review. An example can be found in [http://www.lumiera.org/gitweb?p=lumiera/ct;a=blob;f=tests/backend/test-interfaces.c;h=fb1c4d30a34414767a313d24df60e679c96ad2a7;hb=7323114e77348995ccaf03417136aef7ee332776 tests/backend/test-interfaces.c]
An interface is a list of &quot;slots&quot; mapping functions. The interface descriptor is itself realised as interface, an thus can be versioned, extended and specialised. By use of some glue code and macros we create a simple Interface Definition Language
* after exporting a header with the C interface, including the types to be used...
* LUMIERA_INTERFACE_DECLARE creates an interface description (i.e. the official interface)
* implementing such an interface can be done in 3 major ways
* LUMIERA_INTERFACE_INSTANCE creates an instance on-the-fly (e.g. for descriptors)
* LUMIERA_EXPORT for defining a table of functions/interfaces to export from the core
* LUMIERA_PLUGIN for defining an interface table for functions located within a dynlib module (plugin)
* besides, with LUMIERA_INTERFACE_INLINE you can create a function on-the-fly while LUMIERA_INTERFACE_MAP maps onto an existing function directly
The plugin loading system cares for mapping the given implementation function to the interface slots. Interfaces from the core need to be registered before they can be used, while for plugins this is done automatically on loading the module. The client code later just calls {{{interface_open()}}} and {{{interface_close()}}} where it doesn't matter anymore if the invoked function is in the core or loaded from an dynlib (plugin); loader, registry and/or plugin-DB shall manage it transparently.
Version numbering starts with 1 and uses minor version numbers for compatible changes and major version numbers for everything that breaks existing asumptions. Version number zero is reserved for experimental work and per definition always the most recent version number.
The system is designed to be very flexible and extensible, but this foundation really needs thorough review.
Joelholdworth expresses some concern regarding the UIDs in octal notation used within the interface description. Cehteh explains they never need to be specified by client code. They are just distinctive IDs and provided for some special case within the plugin loader / serializer. He plans to provide a simple tool which automatically replaces a $LUIDGEN with such a bitstring. The octal notation was chosen, because it is the most compact albeit portable notation possible in C source code.
!!Conclusion
looks good, agreement by all core devs.
Should be reviewed and investigated in detail to find any hidden problems.
!Next meeting
There were some problems with the meeting schedule. Using the first week of month seems to be problematic. We'll try with second wednesday...
The next meeting is scheduled for ''Wednesday Nov 12 2008 19:30 UTC'' at #lumiera
</pre>
</div>
<div title="IRC_log_BufferAllocation_2008-06" modifier="Ichthyostega" created="200806211624" tags="irclog excludeMissing" changecount="1">
<pre>! 5.June 2008 on #lumiera
__cehteh__ and __ichthyo__
@ -2152,23 +2439,26 @@ This distributed wiki might be used instead the pipapo.org wiki, investigate tha
Wiki works. It is simple to use and just flexible enough to handle the task. I don't go to install any other software for such tasks on my server. While the design progresses I'd propose to move our work into git repositories and eventually phase this wiki pages out anyways. I'd rather like to start out distributed/git right away .. but git gives us only a fine storage layer, for a design process we need some good presentation layer (later when using git and starting the implementation everyones favorite editor serves for that) I have no better ideas yet to solve the presentation problem other than using this wiki (or maybe Bouml).
</pre>
</div>
<div title="LumieraWiki" modifier="Ichthyostega" modified="200808280150" created="200706172308" tags="portal" changecount="41">
<div title="LumieraWiki" modifier="Ichthyostega" modified="200810151550" created="200706172308" tags="portal" changecount="46">
<pre>[&lt;img[draw/LumiLogo.png]]
''Lumiera'' is the emerging professional non linear video editor for Linux
This is the entry point to several [[TiddlyWiki]]-Pages containing the developer and design documentation.
This is the entry point to several [[TiddlyWiki]]-Pages containing the developer and design documentation. The documentation is split in several parts corresponding to the parts of the application. Those TiddlyWiki pages are self modifying HTML pages; we include them into the GIT source tree. For the future we plan to move the contents of these developer doc wikis into a GIT backed uWiki (still under development as of 10/2008)
* we maintain (semi-) final design docs in DesignDocumentation
* Things get often worked out on IRC, see IRC-Transcripts for decisions made there and not yet put into the proper documentation places
* Things get often worked out on IRC, see IRC-Transcripts for protocols, transcripts and decisions made there
----
!Architecture and Subsystems
to get started, we create design drafts emphasizing different aspects and regions of Lumiera
&amp;rarr; see the ArchitectureOverview
* Cehteh works on the data backend, see [[this page|backend.html]]
* Ichthyo focuses mainly on Edit operations and Builder, [[see this separate page|renderengine.html]]
* Joel started with a GUI implementation based on GTK
* Joel builds the Lumiera GUI based on GTK
* Gmerlin is in charge of [[GAVL|http://gmerlin.sourceforge.net/gavl.html]] for processing of video data
* Some tools which don't fit somewhere else and are used everywhere are put into a [[Support Library|support_library.html]]
@ -3209,10 +3499,11 @@ Typically, one would just write the necessary definitions as they come into one
Moreover, one could simply list all needed files or break everything down into a hierarchical build. But instead, we use for most objects a helper function (located in {{{admin/scons/Buildhelper.py}}}) called {{{srcSubtree()}}}, which will scan a directory tree and add all {{{'*.c','*.cpp','*.cc'}}} - files as Object nodes to the build process. Besides that, we use the //hierarchical aproach rather reluctant//: at the moment, only the subtree for separate tools and the tests-directory have a separate buildscript. Probably, the subtree for plugins will get one as well at some point in the future.
</pre>
</div>
<div title="ShortCuts" modifier="MichaelPloujnikov" modified="200706270305" created="200706260438" tags="portal" changecount="7">
<div title="ShortCuts" modifier="Ichthyostega" modified="200810151609" created="200706260438" tags="portal" changecount="8">
<pre>~~This small Tiddler contains usefull Shortcuts, Info, Links~~
*[[Wiki-Markup|http://tiddlywiki.com/#MainFeatures]]
*[[Wiki-Markup|http://tiddlywiki.org/wiki/TiddlyWiki_Markup]]
*[[Design-Process|http://www.pipapo.org/pipawiki/Lumiera/DesignProcess]]
*
----
</pre>
@ -4597,82 +4888,11 @@ function addKeyDownHandlers(e)
}
//}}}</pre>
</div>
<div title="TiddlyWiki" modifier="Ichthyostega" modified="200708120058" created="200706260506" tags="excludeMissing" changecount="4">
<div title="TiddlyWiki" modifier="Ichthyostega" modified="200810151552" created="200706260506" tags="excludeMissing" changecount="5">
<pre>The Name of the Software driving this Wiki. Is is written completely in ~JavaScript and contained in one single HTML page.
Thus no server and no network connection is needed. Simply open the file in your browser and save changes locally. As the wiki HTML is located in the Lumiera source tree, all changes will be managed and distributed via [[GIT|GitNotes]]. While doing so, you sometimes will have to merge conflicing changes manually in the HTML source. There is a 'empty.html' in the same folder serving as template for generating new wikis. Please refrain from editing it.
* see GettingStarted
* see [[Homepage|http://tiddlywiki.com]], [[Wiki-Markup|http://tiddlywiki.com/#MainFeatures]]
</pre>
</div>
<div title="TimeHandling" modifier="Ichthyostega" modified="200810050506" created="200810050456" changecount="8">
<pre>/%||'''State'''||''Final''||%/
||'''State'''||''Draft''||
||'''Date'''||[[Date(2007-06-21T05:12:03Z)]]||
||'''Proprosed by'''||[&quot;Ichthyostega&quot;]||
!time handling
how to handle time values in the code and which policy to aply to the &quot;current&quot; position
!!Description
# Representation of time values
#* we use an uniform time type. Time is time, not frames, samples etc.
#* all timings in Lumiera are based on integral datatypes
#* we use a fixed, very fine grid, something of the sort of microseconds
#* the internal representation is based on a {{{typedef int64_t gavl_time_t}}}
#* we use a set of library routines and convenience-methods to
#** get time in different formats (fractional seconds, frame counts)
#** calculate with time values (overloaded operators)
#* time measurement is zero based (of course :-P )
# Quantizing to a frame index or similar
#* quantizing/rounding shall happen only once at a defined point in the calculation chain and, if in doubt, be done always as late as possible.
#* values needing to be quantized to time (grid) positions are calculated by half-way rounding, but the result should not depend on the actual zero-point of the scale (i.e. {{{floor(0.5+val)}}}, thus quant(0.5) yields 1, quant(0.49) yields 0, quant(-0.5) yields 0 )
# Position of frames[&gt;img[draw/FramePositions1.png]]
#* frame numbers are zero based and Frame 0 starts at time=0 (or whatever the nominal start time is)
#* each frame starts when the locator hits its lower border (inclusively) and ends when the locator is on its upper border (exclusively)
#** when the locator snaps to frames this means it can be placed on the start positions of the frames solely
#** when the locator is placed on such a start position, this means //always// displaying the frame starting at this position, irrespective of playback direction.
# Current position for keyframe nodes and automation[&gt;img[draw/FramePositions2.png]]
#* when parameter values for plugins/automation need to be retrieved on a per frame base (which normally is the case), for each frame there is a well defined __//point of evalutation//__ time position, irrespective of the playback direction
#* there is no single best choice where to put this &quot;POE&quot;, thus we provide a switch
#** //point of evalutation// of the automation is in the middle of the timespan covered by a frame
#** //point of evalutation// is on the lower bound of each frame
#** maybe additional position or fraction (?)
#* moreover, we provide an option to snap the keyframe nodes to the //point of evalutation// within each frame or to be able to move them arbitrarily
#* when keyframes are set by tweaking of parameters, they are located at the //point of evalutation// position.
!!!!Tasks
* figure out what has to be done when switching the &quot;current position&quot; policy on a existing project
!!!Alternatives
Leave everything as in Cinelerra2, i.e. show frames after the locator has passed over them, behave differnt when playing backwards and set the keyframes on the position of the locator but use them on the frame actually to be shown (which differs according to the playback direction but is always &quot;one off&quot;).
Why not? because it makes frame-precise working with keyframes a real pain and even creates contradictory situations when you
switch back and forward while tweaking.
Similar for the issues with quantized values. At first sight, e.g. directly using the frame numbers as coordinates (as Cinelerra does) seems to be clever, but on the long run we get lots of case distinctions scattered all over the code. Thus better use one uniform scheme and work with precise time values as long as possible and only quantize for rendering a given frame.
!!Rationale
The intention is to make time handling and calculations as uniform and &quot;rational&quot; as possible. We try to stick to the precise mathematical values and let the calculations just yield an result in an uniform manner, instead of sticking to &quot;simple&quot; values like frame counts or even a session-wide frame rate
# time and interval calculations are tricky. Solve this question once and be done.
# rounding is always dangerous, rounded values are not the more &quot;clean&quot; values. The floor-rounding rule is chosen, because the length of an interval after quantizion should not depend on the position in relation to the zero point. The usual mathematical rounding behaves &quot;symmetrical&quot; to the zero point, which could yield a different length after quantizion if an interval contains the zero point
# this is based on the analoy with real film running through a film projector (or the usual fencepost problem)
# while using the actual position of the locator as the &quot;current&quot; position for keyframes seems more natural at first, it crates problems when mixing footage with different framerate or when using a low-framerate proxy footage
!Comments
This is the summary of a discussion cehteh, Plouj and ichthyo just had on irc.
-- [&quot;Ichthyostega&quot;] //2007-06-21T05:12:03Z//
We use Gavl now
-- [&quot;ct&quot;] //2008-03-05T16:19:22Z//
I've tidied up this old design proposal, we could make it final now. I've changed the rounding rule, please check if it's OK. In the original proposal, we wanted to use the common mathematical rounding rule, i.e. round(-x) = - round(x) . I changed this, because of the danger of interval lengts or alignment to &quot;jump&quot; dependant on the position in relation to the time zero point.
-- [&quot;Ichthyostega&quot;] //2008-10-04T22:47:54Z//
* see [[Homepage|http://tiddlywiki.com]], [[Wiki-Markup|http://tiddlywiki.org/wiki/TiddlyWiki_Markup]]
</pre>
</div>
<div title="whatInBOUML" modifier="Ichthyostega" modified="200708051535" created="200706260559" tags="discuss policy" changecount="3">

View file

@ -928,13 +928,18 @@ TertiaryMid: #99a
TertiaryDark: #667
Error: #f88</pre>
</div>
<div title="ConManager" modifier="Ichthyostega" created="200806050208" tags="def Builder" changecount="1">
<pre>The Connection Manager is a __Facade__ for querying information and deriving decisions regarding various aspects of data streams and possible connections.
* retrieve information about capabilities of a stream type given by ID
<div title="ConManager" modifier="Ichthyostega" modified="200810060300" created="200806050208" tags="def Builder" changecount="4">
<pre>The Connection Manager is a service for wiring connections and for querying information and deriving decisions regarding various aspects of data streams and the possibility of connections. The purpose of the Connection Manager is to isolate the [[Builder]], which is client of this information and decision services, from the often convoluted details of type information and organizing a connection.
!control connections
my intention was that it would be sufficient for the builder to pass an connection request, and the Connection Manager will handle the details of establishing a control/parameter link.
{{red{TODO: handling of parameter values, automation and control connections still need to be designed}}}
!data connections
Connecting data streams of differing type involves a StreamConversion. Mostly, this aspect is covered by the [[stream type system|StreamType]]. The intended implementation will rely partially on [[rules|ConfigRules]] to define automated conversions, while other parts need to be provided by hard wired logic. Thus, regarding data connections, the ConManager can be seen as a specialized Facade and will delegate to the &amp;rarr; [[stream type manager|STypeManager]]
* retrieve information about capabilities of a stream type given by ID
* decide if a connection is possible
* retrieve a //strategy// for implementing a connection
In the intended implementation, a good deal of this functionality will actually be implemented by [[rules|ConfigRules]], while other parts need to be provided by hard wired logic, at least as a fallback. Anyway, the purpose of the Connection Manager ois to isolate the [[Builder]], which is client of this information and decision services, from these details
</pre>
</div>
<div title="ConfigQuery" modifier="Ichthyostega" modified="200804110335" created="200801181308" tags="def" changecount="5">
@ -1058,7 +1063,7 @@ As we don't have a Prolog interpreter on board yet, we utilize a mock store with
{{{default(Obj)}}} is a predicate expressing that the object {{{Obj}}} can be considered the default setup under the given conditions. Using the //default// can be considered as a shortcut for actually finding a exact and unique solution. The latter would require to specify all sorts of detailed properties up to the point where only one single object can satisfy all conditions. On the other hand, leaving some properties unspecified would yield a set of solutions (and the user code issuing the query had to provide means for selecting one soltution from this set). Just falling back on the //default// means that the user code actually doesn't care for any additional properties (as long as the properties he //does// care for are satisfied). Nothing is said specifically on //how//&amp;nbsp; this default gets configured; actually there can be rules //somewhere,// and, additionally, anything encountered once while asking for a default can be re-used as default under similar circumstances.
&amp;rarr; [[implementing defaults|DefaultsImplementation]]</pre>
</div>
<div title="DesignDecisions" modifier="Ichthyostega" modified="200805300045" created="200801062209" tags="decision design discuss" changecount="18">
<div title="DesignDecisions" modifier="Ichthyostega" modified="200809230234" created="200801062209" tags="decision design discuss" changecount="20">
<pre>Along the way of working out various [[implementation details|ImplementationDetails]], decisions need to be made on how to understand the different facilities and entities and how to tackle some of the problems. This page is mainly a collection of keywords, summaries and links to further the discussion. And the various decisions should allways be read as proposals to solve some problem at hand...
''Everything is an object'' &amp;mdash; of course, that's a //no-brainer // todays. Rather, important is what is not &quot;an object&quot;, meaning it can't be arranged arbitrarily
@ -1072,6 +1077,10 @@ We ''separate'' processing (rendering) and configuration (building). We have a [
An [[EDL]] is just a collection of configured and placed objects (and has no additional, fixed structure). [[Tracks|Track]] form a mere organisational grid, they are grouping devices not first-class entities (a track doesn't &quot;have&quot; a pipe or &quot;is&quot; a video track and the like; it can be configured to behave in such manner by using placements though). [[Pipes|Pipe]] are hooks for making connections and are the only facility to build processing chains. We have global pipes, and each clip is built around a lokal [[source port|ClipSourcePort]] &amp;mdash; and that's all. No special &quot;media viewer&quot; and &quot;arranger&quot;, no special role for media sources, no commitment to some fixed media stream types (video and audio). All of this is sort of pushed down to be configuration, represented as asset of some kind. For example, we have [[processing pattern|ProcPatt]] assets to represent the way of building the source network for reading from some media file (including codecs treated like effect plugin nodes)
''State'' is rigorously ''externalized'' and operations are to be ''scheduled'', to simplify locking and error handling. State is either treated similar to media stream data (as addressable and cacheable data frame), or is represented as &quot;parameter&quot; to be served by some [[parameter provider|ParamProvider]]. Consequently, [[Automation]] is just another kind of parameter, i.e. a function &amp;mdash; how this function is calculated is an encapsulated implementation detail (we don't have &quot;bezier automation&quot;, and then maybe a &quot;linear automation&quot;, a &quot;mask automation&quot; and yet another way to handle transitions)
Deliberately there is an limitaion on the flexibility of what can be added to the system via Plugins. We allow configuration and parametrisation to be extended and we allow processing and data handling to be extended, but we disallow extensions to the fundamental structure of the system by plugins. They may provide new implementations for already known subsystems, but they can't introduce new subsystems not envisioned in the general design of the application.
* thus fixed assortments include: the possbile kinds of MObject and [[Asset]], the possible automation parameter data types, the supported kinds of plugin systems
* while plugins may extend: the supported kinds of media, the [[media handling libraries|MediaImplLib]] used to deal with those media, the session storage backends, the behaviour of placments
</pre>
</div>
<div title="DesignGoals" modifier="Ichthyostega" modified="200805300046" created="200706210557" tags="design" changecount="20">
@ -1320,6 +1329,11 @@ Slider.prototype.stop = function()
}
//}}}</pre>
</div>
<div title="GAVL" modifier="Ichthyostega" created="200809220251" tags="def" changecount="1">
<pre>The ''Gmerlin Audio Video Library''. &amp;rarr; see [[homepage|http://gmerlin.sourceforge.net/gavl.html]]
Used within Lumiera as a foundation for working with raw video and audio media data
</pre>
</div>
<div title="GOPs" modifier="Ichthyostega" modified="200706220333" created="200706220301" tags="def" changecount="2">
<pre>__G__roup __of__ __P__ictures: several compressed video formats don't encode single frames. Normally, such formats are considered mere //delivery formates// but it was one of the key strenghts of Cinelrra from start to be able to do real non linear editing on such formats (like the ~MPEG2-ts unsed in HDV video). The problem of course is that the data backend needs to decode the whole GOP to be serve single raw video frames.
@ -1365,7 +1379,7 @@ Besides routing to a global pipe, wiring plugs can also connect to the source po
Finally, this example shows an ''automation'' data set controlling some parameter of an effect contained in one of the global pipes. From the effect's POV, the automation is simply a ParamProvider, i.e a function yielding a scalar value over time. The automation data set may be implemented as a bézier curve, or by a mathematical function (e.g. sine or fractal pseudo random) or by some captured and interpolated data values. Interestingly, in this example the automation data set has been placed relatively to the meta clip (albeit on another track), thus it will follow and adjust when the latter is moved.
</pre>
</div>
<div title="ImplementationDetails" modifier="Ichthyostega" modified="200808151447" created="200708080322" tags="overview" changecount="26">
<div title="ImplementationDetails" modifier="Ichthyostega" modified="200809130314" created="200708080322" tags="overview" changecount="28">
<pre>This wiki page is the entry point to detail notes covering some technical decisions, details and problems encountered in the course of the implementation of the Lumiera Renderengine, the Builder and the related parts.
* [[Packages, Interfaces and Namespaces|InterfaceNamespaces]]
@ -1383,7 +1397,7 @@ Finally, this example shows an ''automation'' data set controlling some paramete
* [[identifying the basic Builder operations|BasicBuildingOperations]] and [[planning the Implementation|PlanningNodeCreatorTool]]
* [[how to handle »attached placement«|AttachedPlacementProblem]]
* working out the [[basic building situations|BuilderPrimitives]] and [[mechanics of rendering|RenderMechanics]]
* how to classify and [[describe media stream types|StreamType]]
* how to classify and [[describe media stream types|StreamType]] and how to [[use them|StreamTypeUse]]
</pre>
</div>
<div title="ImplementationGuidelines" modifier="Ichthyostega" modified="200711210542" created="200711210531" tags="discuss draft" changecount="7">
@ -1832,6 +1846,22 @@ __5/2008__: the allocation mechanism can surely be improved later, but for now I
&amp;rarr; see also LoadingMedia
</pre>
</div>
<div title="MediaImplLib" modifier="Ichthyostega" modified="200809251942" created="200809220304" tags="def spec" changecount="5">
<pre>The Proc-Layer is designed such as to avoid unnecessary assumptions regarding the properties of the media data and streams. Thus, for anything which is not completely generic, we rely on an abstract [[type description|StreamTypeDescriptor]], which provides a ''Facade'' to an actual library implementation. This way, the fundamental operations can be invoked, like allocating a buffer to hold media data.
In the context of Lumiera and especially in the Proc-Layer, __media implementation library__ means
* a subsystem which allows to work with media data of a specific kind
* such as to provide the minimal set of operations
** allocating a frame buffer
** describing the type of the data within such a buffer
* and this subsystem or external library has been integrated to be used through Lumiera by writing adaptation code for accessing these basic operations through the [[implementation facade interface|StreamTypeImplFacade]]
* such a link to an type implementation is registered and maintained by the [[stream type manager|STypeManager]]
!Problem of the implementation data types
Because we deliberately won't make any asumptions about the implementation library (besides the ones imposed indirectly by the facade interface), we can't integrate the data types of the library first class into the type system. All we can do is to use marker types and rely on the builder to have checked the compatibility of the actual data beforehand.
It would be possible to circumvent this problem by requiring all supported implementation libraries to be known at compile time, because then the actual media implementation type could be linked to a facade type by generic programming. Indeed, Lumiera follows this route with regards to the possible kinds of MObject or [[Asset]] &amp;mdash; but to the contraty, for the problem in question here, being able to include support for a new media data type just by adding a plugin by far outweights the benefits of compile-time checked implementation type selection. So, as a consequence of this design decision we //note the possibility of the media file type discovery code to be misconfigured// and select the //wrong implementation library at runtime.// And thus the render engine needs to be prepared for the source reading node of any pipe to flounder completely, and protect the rest of the system accordingly
</pre>
</div>
<div title="MemoryManagement" modifier="Ichthyostega" modified="200808110208" created="200708100225" tags="impl decision discuss" changecount="14">
<pre>Of course: Cinelerra currently leaks memory and crashes regularilly. For the newly written code, besides retaining the same level of performance, a main goal is to use methods and techniques known to support the writing of quality code. So, besides the MultithreadConsiderations, a solid strategy for managing the ownership of allocated memory blocks is necessary right from start.
@ -3196,6 +3226,9 @@ __see also__
Rendering can be seen as a passive service available to the Backend, which remains in charge what to render and when. Render processes may be running in parallel without any limitations. All of the storage and data management falls into the realm of the Backend. The render nodes themselves are ''completely stateless'' &amp;mdash; if some state is necessary for carrying out the calculations, the backend will provide a //state frame// in addition to the data frames.</pre>
</div>
<div title="STypeManager" modifier="Ichthyostega" created="200809220230" changecount="1">
<pre>A facility allowing the Proc-Layer to work with abstracted [[media stream types|StreamType]], linking (abstract or opaque) [[type tags|StreamTypeDescriptor]] to an [[library|MediaImplLib]], which provides functionality for acutally dealing with data of this media stream type. Thus, the stream type manager is a kind of registry of all the external libraries which can be bridged and accessed by Lumiera (for working with media data, that is). The most basic set of libraries is instelled here automatically at application start, most notably the [[GAVL]] library for working with uncompressed video and audio data. //Later on, when plugins will introduce further external libraries, these need to be registered here too.//</pre>
</div>
<div title="Session" modifier="Ichthyostega" modified="200712100526" created="200712100525" tags="def" changecount="3">
<pre>The Session contains all informations, state and objects to be edited by the User. From a users view, the Session is synonymous to the //current Project//. It can be saved and loaded. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one (or several) collections within the Session, which we call [[EDL (Edit Decision List)|EDL]]. &amp;rarr; [[Session design overview|SessionOverview]]
@ -3310,22 +3343,30 @@ if (oldText.indexOf(&quot;SplashScreen&quot;)==-1)
* in a future version, it may also encapsulate the communication in a distributed render farm
</pre>
</div>
<div title="StreamPrototype" modifier="Ichthyostega" modified="200808152103" created="200808152042" tags="def spec" changecount="7">
<div title="StreamConversion" modifier="Ichthyostega" modified="200810060308" created="200810020337" tags="design spec" changecount="4">
<pre>Conversion of a media stream into a stream of another type is done by a processor module (plugin). The problem of finding such a module is closely related to the StreamType and especially [[problems of querying|StreamTypeQuery]] for such. (The builder uses a special Facade, the ConManager, to access this functionality). There can be different kinds of conversions, and the existance or non-existance of such an conversion can influence the stream type classification.
* different //kinds of media// can be ''transformed'' into each other
* stream types //subsumed// by a given prototype should be ''lossless convertible'' and thus can be considered //equivalent.//
* besides, between different stream //implementation types,// there can be a ''rendering'' (lossy conversion) &amp;mdash; or no conversion at all.
</pre>
</div>
<div title="StreamPrototype" modifier="Ichthyostega" modified="200809120021" created="200808152042" tags="def spec" changecount="10">
<pre>The stream Prototype is part of the specification of a media stream's type. It is a semantic (or problem domain oriented) concept and should be distinguished from the actual implementation type of the media stream. The latter is provided by an [[library implementation|StreamTypeImplFacade]]. While there are some common predefined prototypes, mostly, they are defined within the concrete [[Session]] according to the user's needs.
Prototypes form an open (extensible) collection, though each prototype belongs to a specific media kind ({{{VIDEO, IMAGE, AUDIO, MIDI,...}}}). The ''distinguishing property'' of a stream prototype is that any [[Pipe]] can process //streams of a specific prototype only.// Thus, two streams with different prototype can be considered &quot;something quite different&quot; from the users point of view, while two streams belonging to the same prototype can be considered equivalent (and will be converted automatically when their implementation types differ). Note this definition is //deliberately fuzzy,// because it depends on the actual situation of the project in question.
Prototypes form an open (extensible) collection, though each prototype belongs to a specific media kind ({{{VIDEO, IMAGE, AUDIO, MIDI,...}}}).
The ''distinguishing property'' of a stream prototype is that any [[Pipe]] can process //streams of a specific prototype only.// Thus, two streams with different prototype can be considered &quot;something quite different&quot; from the users point of view, while two streams belonging to the same prototype can be considered equivalent (and will be converted automatically when their implementation types differ). Note this definition is //deliberately fuzzy,// because it depends on the actual situation of the project in question.
Consequently, as we can't get away with an fixed Enum of all stream prototypes, the implementation must rely on a query interface. The intention is to provide a basic set of rules for deciding queries about the most common stream prototypes; besides, a specific session may inject additional rules or utilize a completely different knowledge base. Thus, for a given StreamTypeDescriptor specifying a prototype
* we can get a [[default|DefaultsManagement]] implementation type
* we can get a default prototype to a given implementation type by a similar query
* we can query if a implementation type in question can be //subsumed// under this prototype
* we can query if a implementation type in question can be //subsumed// by this prototype
* we can determine if another prototype is //convertible//
!!Examples
NTSC and PAL video, video versus digitized film, HD video versus SD video, 3D versus flat video, cinemascope versus 4:3, stereophonic versus monaural, periphonic versus panoramic sound, Ambisonics versus 5.1, dolby versus dts,...
NTSC and PAL video, video versus digitized film, HD video versus SD video, 3D versus flat video, cinemascope versus 4:3, stereophonic versus monaural, periphonic versus panoramic sound, Ambisonics versus 5.1, dolby versus linear PCM...
</pre>
</div>
<div title="StreamType" modifier="Ichthyostega" modified="200808152026" created="200808060244" tags="spec discuss draft" changecount="4">
<div title="StreamType" modifier="Ichthyostega" modified="200809280108" created="200808060244" tags="spec discuss draft" changecount="9">
<pre>//how to classify and describe media streams//
Media data is understood to appear structured as stream(s) over time. While there may be an inherent internal structuring, at a given perspective ''any stream is a unit and homogeneous''. In the context of digital media data processing, streams are always ''quantized'', which means they appear as a temporal sequence of data chunks called ''frames''.
@ -3347,8 +3388,8 @@ A stream type is denoted by a StreamTypeID, which is an identifier, acting as an
!! Classification
Within the Proc-Layer, media streams are treated largely in a similar manner. But, looking closer, note everything can be connected together, while on the other hand there may be some classes of media streams which can be considered //equivalent// in most respects. Thus, it seems reasonable to separate the distinction between various media streams into several levels
* Each media belongs to a fundamental ''kind'' of media, examples being __Video__, __Image__, __Audio__, __MIDI__,... Media streams of different kind can be considered somewhat &quot;completely separate&quot; &amp;mdash; just the handling of each of those media kinds follows a common //generic pattern// augmented with specialisations. Basically, it is //impossible to connect// media streams of different kind. Under some circumstances there may be the possibility of a //transformation// though. For example, a still image can be incorporated into video, sound may be visualized, MIDI may control a sound synthesizer.
* Below the level of distinct kinds of media streams, within every kind we have an open ended collection of ''prototypes'', which, when compared directly may each be quite distinct and different, but which may be //rendered//&amp;nbsp; into each other. For example, we have stereoscopic (3D) video and we have the common flat video lacking depth information, we have several spatial audio systems (Ambisonics, Wave Field Synthesis), we have panorama simulating sound systems (5.1, 7.1,...), we have common stereophonic and monaural audio. It is considered important to retain some openness and configurability within this level of distinction, which means this classification should better be done by rules then by setting up a fixed property table. For example, it may be desirable for some production to distinguish between digitized film and video NTSC and PAL, while in another production everything is just &quot;video&quot; and can be converted mostly automatically. The most noticeable consequence of such a distinction is that any Bus or [[Pipe]] is always limited to a media stream of a single prototype. (&amp;rarr; [[more|StreamPrototype]])
* Besides the distinction by prototypes, there are the various media ''implementation types''. This classification is not necessarily hierarchically related to the prototype classification, while in practice commonly there will be some sort of dependency. For example, both stereophonic and monaural audio may be implemented as 96kHz 24bit PCM with just a different number of channel streams, as well as we may have a dedicated stereo audio stream with two channels multiplexed into a single stream. For dealing with media streams of various implementation type, we need library routines, which also yield a type classification system. Most notably, for raw sound and video data we use the GAVL library, which defines a classification system for buffers and streams.
* Below the level of distinct kinds of media streams, within every kind we have an open ended collection of ''prototypes'', which, when compared directly, may each be quite distinct and different, but which may be //rendered//&amp;nbsp; into each other. For example, we have stereoscopic (3D) video and we have the common flat video lacking depth information, we have several spatial audio systems (Ambisonics, Wave Field Synthesis), we have panorama simulating sound systems (5.1, 7.1,...), we have common stereophonic and monaural audio. It is considered important to retain some openness and configurability within this level of distinction, which means this classification should better be done by rules then by setting up a fixed property table. For example, it may be desirable for some production to distinguish between digitized film and video NTSC and PAL, while in another production everything is just &quot;video&quot; and can be converted automatically. The most noticeable consequence of such a distinction is that any Bus or [[Pipe]] is always limited to a media stream of a single prototype. (&amp;rarr; [[more|StreamPrototype]])
* Besides the distinction by prototypes, there are the various media ''implementation types''. This classification is not necessarily hierarchically related to the prototype classification, while in practice commonly there will be some sort of dependency. For example, both stereophonic and monaural audio may be implemented as 96kHz 24bit PCM with just a different number of channel streams, as well we may have a dedicated stereo audio stream with two channels multiplexed into a single stream. For dealing with media streams of various implementation type, we need //library// routines, which also yield a //type classification system.// Most notably, for raw sound and video data we use the [[GAVL]] library, which defines a classification system for buffers and streams.
* Besides the type classification detailed thus far, we introduce an ''intention tag''. This is a synthetic classification owned by Lumiera and used for internal wiring decisions. Currently (8/08), we recognize the following intention tags: __Source__, __Raw__, __Intermediary__ and __Target__. Only media streams tagged as __Raw__ can be processed.
!! Media handling requirements involving stream type classification
@ -3356,21 +3397,30 @@ Within the Proc-Layer, media streams are treated largely in a similar manner. Bu
* determine if a given media data source and sink can be connected, and how.
* determine and enumerate the internal structure of a stream.
* discover processing facilities
&amp;rarr; see StreamTypeUse
&amp;rarr; [[querying types|StreamTypeQuery]]
</pre>
</div>
<div title="StreamTypeDescriptor" modifier="Ichthyostega" modified="200808152027" created="200808151505" tags="def" changecount="6">
<div title="StreamTypeDescriptor" modifier="Ichthyostega" modified="200809130314" created="200808151505" tags="def" changecount="7">
<pre>A description and classification record usable to find out about the properties of a media stream. The stream type descriptor can be accessed using an unique StreamTypeID. The information contained in this descriptor record can intentionally be //incomplete,// in which case the descriptor captures a class of matching media stream types. The following information is maintained:
* fundamental ''kind'' of media: {{{VIDEO, IMAGE, AUDIO, MIDI,...}}}
* stream ''prototype'': this is the abstract high level media type, like NTSC, PAL, Film, 3D, Ambisonics, 5.1, monaural,...
* stream ''implementation type'' accessible by virtue of an StreamTypeImplFacade
* the ''intended usage category'' of this stream: {{{SOURCE, RAW, INTERMEDIARY, TARGET}}}.
&amp;rarr; see &amp;raquo;[[Stream Type|StreamType]]&amp;laquo; detailed specification
&amp;rarr; notes about [[using stream types|StreamTypeUse]]
&amp;rarr; more [[about prototypes|StreamPrototype]]</pre>
</div>
<div title="StreamTypeID" modifier="Ichthyostega" created="200808151510" tags="def" changecount="1">
<pre>This ID is an symbolic key linked to a StreamTypeDescriptor. The predicate {{{stream(ID)}}} specifies a media stream with the StreamType as detailed by the corresponding descriptor (which may contain complete or partial data defining the type).</pre>
</div>
<div title="StreamTypeImplFacade" modifier="Ichthyostega" modified="200808151818" created="200808151520" tags="def" changecount="6">
<div title="StreamTypeImplConstraint" modifier="Ichthyostega" modified="200810020230" created="200809220248" tags="def" changecount="2">
<pre>A special kind of media stream [[implementation type|StreamTypeImplFacade]], which is not fully specified. As such, it is supposed there //actually is// an concrete implementation type, while only caring for some part or detail of this implementation to exhibit a specific property. For example, using an type constraint we can express the requirement of the actual implementation of a video stream to be based on ~RGB-float, or to enforce a fixed frame size in pixels.
An implementation constraint can //stand-in// for a completely specified implementation type (meaning it's a sub interface of the latter). But actually using it in this way may cause a call to the [[defaults manager|DefaultsImplementation]] to fill in any missing information. An example would be to call {{{createFrame()}}} on the type constraint object, which means being able to allocate memory to hold a data frame, with properties in compliance with the given type constraint. Of cousre, then we need to know all the properties of this stream type, which is where the defaults manager is queried. This allows session customisation to kick in, but may fail under certain cicumstances.
</pre>
</div>
<div title="StreamTypeImplFacade" modifier="Ichthyostega" modified="200809251940" created="200808151520" tags="def" changecount="7">
<pre>Common interface for dealing with the implementation of media stream data. From a high level perspective, the various kinds of media ({{{VIDEO, IMAGE, AUDIO, MIDI,...}}}) exhibit similar behaviour, while on the implementation level not even the common classification can be settled down to a complete general and useful scheme. Thus, we need separate library implementations for deailing with the various sorts of media data, all providing at least a set of basic operations:
* set up a buffer
* create or accept a frame
@ -3378,6 +3428,105 @@ Within the Proc-Layer, media streams are treated largely in a similar manner. Bu
* ...?
&amp;rarr; see also &amp;raquo;[[Stream Type|StreamType]]&amp;laquo;
//Note:// there is a sort-of &quot;degraded&quot; variant just requiring some &amp;rarr; [[implementation constraint|StreamTypeImplConstraint]] to hold
</pre>
</div>
<div title="StreamTypeQuery" modifier="Ichthyostega" modified="200810060525" created="200809280129" tags="spec draft" changecount="23">
<pre>Querying for media stream type information comes in various flavours
* you may want to find a structural object (pipe, output, processing patten) associated with / able to deal with a certain stream type
* you may need a StreamTypeDescriptor for an existing stream given as implementation data
* you may want to build or complete type information from partial specification.
Mostly, those queries involve the ConfigRules system in some way or the other. The [[prototype-|StreamPrototype]] and [[implementation type|StreamTypeImplFacade]]-interfaces themselves are mostly a facade for issuing appropriate queries. Some objects (especially [[pipes|Pipe]]) are tied to a certain stream type and thus store a direct link to type information. Others are just associated with a type by virtue of the DefaultsManagement.
The //problem// with this pivotal role of the config rules is that &amp;mdash; from a design perspective &amp;mdash; not much can be said specifically, besides //&quot;you may be able to find out...&quot;, &quot;...depends on the defaults and the session configuration&quot;.// This way, a good deal of crucial behaviour is pushed out of the core implementation (and it's quite intentionally being done this way). What can be done regarding the design of the core is mostly to setup a framework for the rules and determine possible ''query situations''.
!the kind of media
the information of the fundamental media kind (video, audio, text, MIDI,...) is assiciated with the prototype, for technical reasons. Prototype information is mandatory for each StreamType, and the impl facade provides a query function (because some implementation libraries, e.g. [[GAVL]], support multiple kinds of media).
!query for a prototype
__Situation__: given an implementation type, find a prototype to subsume it.
Required only for building a complete ~StreamType which isn't known at this point.
The general case of this query is //quite hairy,// because the solution is not necessary clear and unique. And, worse still, it is related to the semantics, requiring semantic information and tagging to be maintained somewhere. For example, while the computer can't &quot;know&quot; what stereopohinc audio is (only a human can by listening to a stereophoic playback and deciding if it actually does convey a spatical sound image), in most cases we can overcome this problem by using the //heuristical rule// of assuming the prototype &quot;stereophonic&quot; when given two identically typed audio channels. This example also shows the necessity of ordering heuristic rules to be able to pick a best fit.
We can inject two different kinds of fallback solutions for this kind of query:
* we can always build a &quot;catch-all&quot; prototype just based on the kind of media (e.g. {{{prototype(video).}}}). This should match with lowest priority
* we can search for existing ~StreamTypes with the same impl type, or an impl type which is //equivalent convertible// (see &amp;rarr; StreamConversion).
The latter case can yield multiple solutions, which isn't any problem, because the match is limited to classes of equivalent stream implementation, which would be subsumed under the same prototype anyway. Even if the registry holds different prototypes linked to the same implementation type, they would be convertible and thus could //stand-in// for one another. Together this results in the implementation
# try to get a direct match to an existing impl type which has an associated (complete) ~StreamType, thus bypassing the ConfigRules system altogether
# run a {{{Query&lt;Prototype&gt;}}} for the given implementation type
# do the search within equivalence class as described above
# fall back to the media kind.
{{red{TODO: how to deal with the problem of hijacking a prototype?}}} &amp;rarr; see [[here|StreamTypeUse]]
!query for an implementation
__Situation 1__: given an partially specified ~StreamType (just an [[constraint|StreamTypeImplConstraint]])
__Situation 2__: find an implementation for a given prototype (without any further impl type guidlines)
Both cases have to go though the [[defaults manager|DefaultsManagement]] in some way, in order to give any default configuration a chance to kick in. This is //one of the most important use cases// of the defaults system: the ability to configure a default fromat for all streams with certain semantic classification. {{{prototype(video)}}} by default is RGBA 24bit non-interlaced for example.
But after having queried the defaults system, there remains the problem to build a new solution (which will then automatically become default for this case). To be more precise: invoking the defaults system (as implemented in Lumiera) means first searching through existing objects encountered as default, and then issuing an general query with the capabilities in question. This general query in turn is conducted by the query type handler and usually consists of first searching existing objects and then creating a new object to match the capabilities. But, as said, the details depend on the type (and are defined by the query handler installed for this type). Translated to our problem here in question, this means //we have to define the basic operations from which a type query handler can be built.// Thus, to start with, it's completely sufficient to wire a call to the DefaultsManagement and assume the current session configuration contains some rules to cover it. Plus being prepared for the query to fail (throw, that is).
Later on this could be augmented by providing some search mechanisms:
* search through existing stream type implementations (or a suitable pre filtered selection) and narrow down the possible result(s) by using the constraint as a filter. Obviously this requires support by the MediaImplLib facade for the implementation in question. (This covers __Situation 1__)
* relate a protoype in question to the other existing prototypes and use the convertibility / subsumption as a filter mechanism. Finally pick an existing impl type which is linked to one of the prototypes found thus far.
Essentially, we need a search mechanism for impltypes and prototypes. This search mechanism is best defined by rules itself, but needs some primitive operations on types, like ennumerating all registered types, filter those selections and match against a constraint.
!query for an (complete) StreamType
All situations discussed thus far can also occur wrapped into and triggered by a query for a complete type. Depending on what part is known, the missing bits will be queried.
Independent from these is __another Situation__ where we query for a type ''by ID''.
* a simple symbolic ID can be found by searching through all existing stream types (Operation supported by the type registry within STypeManager)
* a special ''classificating'' ID can be parsed into the components (media kind, prototype, impltype), resulting in sub searches for these.
{{red{not sure if we want to support queries by symboic ID}}}...problem is the impl type, because probably the library needs to support describing any implementation type by a string. Seemingly GAVL does, but requiring it for every lib?
</pre>
</div>
<div title="StreamTypeUse" modifier="Ichthyostega" modified="200809280320" created="200809130312" tags="draft discuss dynamic" changecount="21">
<pre>Questions regarding the use of StreamType within the Proc-Layer.
* what is the relation between Buffer and Frame?
* how to get the required size of a Buffer?
* who does buffer allocations and how?
Mostly, stream types are used for querying, either to decide if they can be connected, or to find usable processing modules.
Even building a stream type from partial information involves some sort of query.
&amp;rarr; more on [[media stream type queries|StreamTypeQuery]]
!creating stream types
seemingly stream types are created based on an already existing media stream (or a Frame of media data?). {{red{really?}}}
The other use case seems to be that of an //incomplete// stream type based on a [[Prototype|StreamPrototype]]
!Prototype
According to my current understanding, a prototype is merely a classification entity. But then &amp;mdash; how to bootstrap a Prototype?
And how to do the classification of an existing implementation type.
Besides, there is the problem of //hijacking a prototype:// when a specific implementation type gets tied to a rather generic protoype, like {{{protoype(video)}}}, how to comply to the rule of prototypes subsuming a class of equivalent implementations?
!Defaults and partial specification
A StreamType need not be completely defined. It is sufficient to specify the media kind and the Prototype. The implementation type may be just given as a constraint, thus defining some properties and leaving out others. When creating a frame buffer based upon such an //incomplete type,// [[defaults|DefaultsManagement]] are queried to fill in the missing parts.
Constraints are objects provided by the Lumiera core, but specialized to the internals of the actual implementation library.
For example there might be a constraint implementation to force a specific {{{gavl_pixelformat_t}}}.
!the ID problem
Basically I'd prefer the ~IDs to be real identifiers. So they can be used directly within rules. At least the Prototypes //can// have such a textual identifier. But the implementation type is problematic, and consequently the ID of the StreamType as well. Because the actual implementation should not be nailed down to a fixed set of possibilities. And, generally, we can't expect an implementation library to yield textual identifiers for each implementation type. //Is this really a problem? {{red{what are the use cases?}}}//
As far as I can see, in most cases this is no problem, as the type can be retrieved or derived from an existing media object. Thus, the only problematic case is when we need to persist the type information without being able to guarantee the persistence of the media object this type was derived from. For example this might be a problem when working with proxy media. But at least we should be able to create a constraint (partial type specification) to cover the important part of the type information, i.e. the part which is needed to re-create the model even when the original media isn't there any longer.
Thus, //constraints may be viewed as type constructing functors.//
--------------
!use cases
* pulling data from a media file
* connecting pipes and similar wiring problems
* describing the properties of an processor plugin
!! pulling data from a media file
To open the file, we need //type discovery code,// resulting in a handle to some library module for accessing the contents, which is in compliance with the Lumiera application. Thus, we can determine the possible return values of this type discovery code and provide code which wires up a corresponding StreamTypeImplFacade. Further, the {{{control::STypeManager}}} has the ability to build a complete or partial StreamType from
* an ~ImplFacade
* a Prototype
* maybe even from some generic textual ~IDs?
Together this allows to associate a StreamType to each media source, and thus to derive the Prototype governing the immediately connected [[Pipe]]
A pipe can by design handle data of one Prototype solely.
!! wiring problems
When deciding if a connection can be made, we can build up the type information starting out from the source. (this requires some work, but it's //possible,// generally speaking.). Thus, we can allways get an ~ImplType for the &quot;lower end&quot; of the connection, and at least a Prototype for the &quot;output side&quot; &amp;mdash; which should be enough to use the query functions provided by the stream type interfaces
!! describing properties
{{red{currently difficult to define}}} as of 9/2008, because the property description of plugins is not planned yet.
My Idea was to use [[type implementation constraints|StreamTypeImplConstraint]] for this, which are a special kind of ~ImplType
</pre>
</div>
<div title="StrongSeparation" modifier="MichaelPloujnikov" modified="200706271504" created="200706220452" tags="design" changecount="5">
@ -4774,6 +4923,15 @@ If ''not processing'' we don't have any input buffers, instead we get our output
Otherwise, in the default case of actually ''processing'' out output, we have to organize input buffers, allocate output buffers, call the {{{process()}}} function of the WiringDescriptor and finally release the input buffers.
</pre>
</div>
<div title="WiringRequest" modifier="Ichthyostega" modified="200810060404" created="200810060344" tags="def spec" changecount="2">
<pre>{{red{This is an early draft as of 9/08}}}
Wiring requests rather belong to the realm of the high-level model, but play an important role in the build process, because the result of &quot;executing&quot; a wiring request will be to establish an actual low-level data connection. Wiring requests will be created automatically in the course of the build process, but they can be created manually and attached to the media objects in the high-level model as a ''wiring plug'', which is a special kind of LocatingPin (&amp;rarr; [[Placement]])
Wiring requests are small stateful value objects. They will be collected, sorted and processed ordered, such as to finish the building and get a completely wired network of processing nodes. Obviously, there needs to be some reference or smart pointer to the objects to be wired, but this information remains opaque.
&amp;rarr; ConManager
</pre>
</div>
<div title="automation" modifier="Ichthyostega" modified="200805300125" created="200805300057" tags="overview" changecount="8">
<pre>The purpose of automation is to vary a parameter of some data processing instance in the course of time while rendering. Thus, automation encompasses all the variability within the render network //which is not a structural change.//