You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
661 lines
26 KiB
661 lines
26 KiB
4 years ago
|
|
||
|
Module System for Transcode 1.1.0 and later
|
||
|
===========================================
|
||
|
|
||
|
Francesco Romani <fromani@gmail.com>, Andrew Church <achurch@achurch.org>
|
||
|
-
|
||
|
Revision 0.5, 17 August 2006
|
||
|
|
||
|
Index:
|
||
|
---------------------------------------------------------------------------
|
||
|
1. Introduction
|
||
|
2. Overview
|
||
|
3. Core API
|
||
|
3.1. What you need to use NMS
|
||
|
3.2. Example code
|
||
|
3.3. The module factory
|
||
|
3.4. Creating and destroying modules
|
||
|
3.5. TCModule
|
||
|
3.6. Using modules
|
||
|
4. Plugin API
|
||
|
4.1. What you need to use NMS (as a plugin writer)
|
||
|
4.2. Example code
|
||
|
4.3. Structure of a NMS plugin
|
||
|
4.4. The registration process
|
||
|
5. Plugin-Writing-HOWTO
|
||
|
6. Internal structure
|
||
|
6.1. Why the factory?
|
||
|
6.2. About multithreading safeness
|
||
|
6.3. On explicit reference counting
|
||
|
6.4. Possibile API and ABI breakage
|
||
|
6.5. init VS configure, fini VS stop
|
||
|
6.6. A bit more about multiplexors and demultiplexors
|
||
|
7. Final notes
|
||
|
8. Appendix A: planned improvements in 1.2.0 and beyond
|
||
|
|
||
|
|
||
|
***
|
||
|
|
||
|
1. Introduction
|
||
|
---------------------------------------------------------------------------
|
||
|
|
||
|
This document provides basic informations about the new module system
|
||
|
introduced in transcode 1.1.0. New system has API, ABI and even semantic
|
||
|
incompatible with old one. This breakage was needed to address the
|
||
|
recognized problems of old model. We (designers and coders) hope that new
|
||
|
one will serve better our purposes. Anyway, new model hasn't any claim of
|
||
|
generality or effectiveness outside transcode use cases: new API was
|
||
|
designed to be the simplest and cleanest thing that work in transcode
|
||
|
environment, and it doesn't provide any guarantee outside this field.
|
||
|
I (Francesco) have chosen to reimplement our module system from scratch,
|
||
|
despite the fact that well-known libraries such glib provides own ones,
|
||
|
to lower as much as possible the dependencies count for transcode itself.
|
||
|
Other developers agrees on the importance of this objective, where it
|
||
|
is feasible to do (of course we hardly reimplement from scratch some
|
||
|
Audio/Video codecs!).
|
||
|
Header and source code files was written trying to achieve readability
|
||
|
and clarity. Reader is encouraged to take a look at source code and,
|
||
|
especially, header files to get more informantions and more precise
|
||
|
documentation about the functions and data structures provided.
|
||
|
|
||
|
Feel free to suggest improvements to API and/or to this documentation.
|
||
|
PLEASE! report inconsistencies between this documentation and header
|
||
|
and/or source code files.
|
||
|
Send suggestions on transcode-devel@exit1.org mailing list.
|
||
|
Help us to make transcode better!
|
||
|
|
||
|
Francesco's notes:
|
||
|
I'm not a native english speaker. Send me corrections about documentation
|
||
|
rather than code, and I will apply as soon as is possible :)
|
||
|
|
||
|
Quick terminology overview:
|
||
|
- NMS:
|
||
|
Acronym of (transcode's) New Module System
|
||
|
- plugin:
|
||
|
a shared object (usually) on disk that implements one or more
|
||
|
'module's.
|
||
|
- module:
|
||
|
the central abstract object handled by NMS.
|
||
|
A 'module' is a piece of C code that respect some given constraints
|
||
|
(see more) and is usable by transcode. Often a 'plugin' implements
|
||
|
only a 'module' (or a single 'module' is packed in a single 'plugin'),
|
||
|
but there isn't a such constraint, that's only the current practice.
|
||
|
- module instance:
|
||
|
a 'module' specify both the procedures and the data needed to be used
|
||
|
properly. We call 'instance' of a module the unshared, private portion
|
||
|
of such data. So, if a 'module' is created and runned multiple times,
|
||
|
each one has his private context and his private data, so everyone can
|
||
|
run independently from each other. Please note that 'modules' _always_
|
||
|
have some common, shared (and unmodifiable) data.
|
||
|
- module class:
|
||
|
every module can belong to one or more 'module class'. A 'module class'
|
||
|
describe what a given module is supposed to do; this usually means
|
||
|
specifyng what functions and/or capabilities a given module supports
|
||
|
and/or provides.
|
||
|
|
||
|
|
||
|
2. Overview
|
||
|
---------------------------------------------------------------------------
|
||
|
|
||
|
The new module system (NMS) aims to provide a generic framework for
|
||
|
module handling through transcode, including external programs and
|
||
|
helper tools like tcmodinfo.
|
||
|
NMS aims also to incourage people writing of clean multi-instance plugins,
|
||
|
avoiding the 'single huge function syndrome' that affects most of filter
|
||
|
plugins as in transcode < 1.1.0. NMS provide a new and richer capabilities
|
||
|
support code, supporting a wider range of plugin classes: no more only
|
||
|
import (demux + decoding), filter and export (encoding + mux).
|
||
|
|
||
|
NMS supports now five module classes, and is a fundamental part of module
|
||
|
revision process taken starting from transcode 1.1.0.
|
||
|
Please note that a given module CAN belong to more than one class (this
|
||
|
means that such module just implements more functions).
|
||
|
|
||
|
- demuxing module:
|
||
|
take care of reading stream data and extract audio stream,
|
||
|
video stream and so on
|
||
|
- decoding module:
|
||
|
decodes A/V frame to raw data
|
||
|
- filter module:
|
||
|
apply some transformation to A/V raw data
|
||
|
- encoding module:
|
||
|
encodes raw data in a user-defined format
|
||
|
- muxing module:
|
||
|
packs encoded data in a user-defined container
|
||
|
|
||
|
More module classes (notably an input and/or output abstraction)
|
||
|
can be added in future releases, but class count should not increase
|
||
|
too much in NMS lifespan.
|
||
|
|
||
|
Exact specification and documentation about such extended module classes
|
||
|
are partially beyond the purpose of this document; they are further
|
||
|
examined only for the parts related to NMS.
|
||
|
|
||
|
NMS has quite different usage from old module system.
|
||
|
A piece of code that want to use a transcode plugin through NMS should
|
||
|
roughly:
|
||
|
|
||
|
- start a module factory: this will initialize the subsystem; the
|
||
|
most important parameter is the module search path, that is no longer
|
||
|
hardcoded into code.
|
||
|
- ask to a module factory to create a given module. This will trasparently
|
||
|
load a plugin if needed, resolve needed symbols, initialize it and
|
||
|
finally pass back as a reference to client code. In short, module factory
|
||
|
does all black magic for you ;)
|
||
|
- use the module exposed functions as you wish.
|
||
|
Above module classes requires roughly the implementation of one module
|
||
|
for each one plus some mandatory support methods. For example, filter
|
||
|
class requires the implementation of 'filter_video' or 'filter_audio'
|
||
|
(or both) operation, (WARNING: as in transcode 1.1.0, this is not
|
||
|
enforced, yet) but a given module can implement more than one class
|
||
|
simply providing more methods implementation.
|
||
|
As an user of a module, just request the operation and check
|
||
|
the returned code :)
|
||
|
Of course, you can also use the new capabilities system to peek what
|
||
|
a loaded module is supposed to do. More on this topic later.
|
||
|
- when you're set, ask to factory to unload the module. You CAN'T just
|
||
|
free your module manually, since factory needs again to do some black
|
||
|
magic to handle things nicely.
|
||
|
- eventually shutdown the module factory itself. Do this only when
|
||
|
you have released all modules instances, or factory will complain loudly.
|
||
|
|
||
|
NMS Core API (from module *user* viewpoint) will be covered with greater
|
||
|
detail into section 3 of this document.
|
||
|
For interested people, section 6 of this document contains design notes
|
||
|
and some documentation about the NMS internals.
|
||
|
|
||
|
From module writer viewpoint, some there are major changes too.
|
||
|
First af all, all new-style modules have a unified entry point with
|
||
|
following signature (defined in tcmodule-plugin.h):
|
||
|
|
||
|
const TCModuleClass *tc_plugin_setup(void);
|
||
|
|
||
|
If NMS code can't find such symbol defined in your shared object,
|
||
|
it assumes that given SO *IS NOT* a valid NMS module, and it will go
|
||
|
ahead.
|
||
|
NMS entry point is no longer the main entry point for a given module,
|
||
|
but it's simply the entry point for whole registration process.
|
||
|
Real execution of module code will happen through some function pointers
|
||
|
that each module should register into core as initialization stage.
|
||
|
This registration happen, as well as other needed intialization code,
|
||
|
into new entry point.
|
||
|
|
||
|
So, NMS requires that each module provides (roughly) a single function
|
||
|
for each implemented operation. Formerly, this was already a good module
|
||
|
writing pratice, but was not required by former old module system which
|
||
|
used a single function interface to do everything.
|
||
|
|
||
|
NMS has also explicit support for module instance data. Each module
|
||
|
descriptor provide an opaque pointer to module-defined data, which is
|
||
|
opaque to core and can be used freely by module code.
|
||
|
|
||
|
To summarize, a NMS-compliant module will
|
||
|
|
||
|
- provide a separate function for each implemented operation, plus
|
||
|
a few function for support routines (initialization, shutdown,
|
||
|
configuration, stop, introspection) which must conform to a
|
||
|
give signature.
|
||
|
Each method will handle explicitely private (instance) data.
|
||
|
- provide a single uniform entry point for registration process.
|
||
|
core uses module specific methods via some function pointers,
|
||
|
so real code can be made static and private; module itself
|
||
|
should give back to core valid function pointers to his methods
|
||
|
as part of registration process
|
||
|
- register his capabilities in the exported module initialziation
|
||
|
hook. This means registration of methods but also notification
|
||
|
of module capabilities. A module can do arbitrary operations
|
||
|
other than required ones, even this should never be needed.
|
||
|
|
||
|
NMS Plugin API (from module *writer* viewpoint) will be covered with greater
|
||
|
detail into section 3 of this document.
|
||
|
Section 4 of this document will provide some hints for a module writer.
|
||
|
|
||
|
|
||
|
3. Core API
|
||
|
---------------------------------------------------------------------------
|
||
|
|
||
|
The reader of this section is encouraged to take a look of documentation
|
||
|
of functions and data structures embedded into header files of NMS to
|
||
|
become confident with the notions exposed here.
|
||
|
Interesting files:
|
||
|
|
||
|
libtc/tcmodule-core.h
|
||
|
libtc/tcmodule-data.h
|
||
|
libtc/tcmodule-info.h
|
||
|
|
||
|
This section will not explore the semantic and the meaning of parameters
|
||
|
of core API functions, interested reader should be better served just
|
||
|
reading comments on interesting header files.
|
||
|
This section will instead explore the semantic of NMS core API and will
|
||
|
serve to basic usage tutorial.
|
||
|
|
||
|
|
||
|
3.1. What you need to use NMS
|
||
|
-----------------------------
|
||
|
|
||
|
To use transcode's NMS, you need to include some header files on your code:
|
||
|
|
||
|
#include "tcmodule-core.h"
|
||
|
#include "tcmodule-info.h"
|
||
|
|
||
|
Build system for transcode take care to setup the right include search path.
|
||
|
Otherwise, you should give explictely to gcc (code isn't tested on
|
||
|
different compilers due to lack of software):
|
||
|
|
||
|
gcc $YOUR_OPTS -I/path/to/tc/src/libtc/ ...
|
||
|
|
||
|
You also need to link libtc.
|
||
|
|
||
|
Once you have set the gritty details, you are read to start.
|
||
|
|
||
|
|
||
|
3.2. Example code
|
||
|
-----------------
|
||
|
|
||
|
Take a look into tools/tcmodinfo to get maybe the simplest way to use
|
||
|
the NMS. tcmodinfo will just load a user-requested module and will print
|
||
|
out it's capabilities. Future releases of this document will perhaps add
|
||
|
more (pseudo)code examples.
|
||
|
|
||
|
You can also want to look NMS bundled test (in testsuite/ and or libtc/, in
|
||
|
latter case test is embedded, as a comment in tcmodule.c) to get some more
|
||
|
examples.
|
||
|
|
||
|
|
||
|
3.3. The module factory
|
||
|
-----------------------
|
||
|
|
||
|
A key element in NMS is the module factory. From the point of view
|
||
|
of a module user, a factory is represented by a totally opaque handler
|
||
|
enterely managed by tcmodule code.
|
||
|
The factory take care of loading plugins (the real shared object holding
|
||
|
plugin code) if needed, unloading them if no longer need, accounting,
|
||
|
and create instances. In short, factory does all the dirty work for you.
|
||
|
|
||
|
In order to obtain, and release, a factory handler, you must use the
|
||
|
tc_new_module_factory and tc_del_module_factory functions.
|
||
|
Arguments and syntax of this functions is documented on tcmodule-core.h
|
||
|
header file.
|
||
|
|
||
|
Client code can theorically request an arbitrary number of factories,
|
||
|
but each factory can handle ONLY modules created by herself. To
|
||
|
request a factory to do an operation on a module NOT built by herself
|
||
|
will cause a undefined behaviour (expect crash or some other weird things).
|
||
|
In a just few words: DON'T DO THIS! :)
|
||
|
In the common case, "one factory will be enough for everyone".
|
||
|
|
||
|
|
||
|
3.4. Creating and destroying modules
|
||
|
------------------------------------
|
||
|
|
||
|
It's really simple. Just ask to your factory to create a brand new module
|
||
|
belonging to a given class and from a given name.
|
||
|
When the module is built, you must configure it passing some options
|
||
|
packed in a string using the configure function (tc_module_configure).
|
||
|
some modules can be reconfigured multiple times, some other can
|
||
|
be reconfigured just the first time; This behaviour is fully
|
||
|
module-(class-)dependent.
|
||
|
Options are specific to a module, and there is no way to describe they
|
||
|
in a general fashion.
|
||
|
Since a module can be (or must be, for multiplexors) reconfigured
|
||
|
a run time, the need for inspecting module settings arise.
|
||
|
NMS provide an explicit operation for inquiry the actual settings of
|
||
|
a module, the 'inspect' operation. Client code can request to know
|
||
|
the status each and/or all module configurable parameters using this
|
||
|
operation.
|
||
|
|
||
|
Please note that NMS *NOT* knows _before_ to loading what every module
|
||
|
is capable to do, nor the class of a given module. Everything
|
||
|
is detected after the loading using new capabilities code.
|
||
|
This means that you can ask to load a given module without to already
|
||
|
know it's class, nor you ask to load all modules of a given class.
|
||
|
Both above requests will lead to an error.
|
||
|
As in transcode 1.1.0, module class and module name are in facts
|
||
|
tightly bound and can't be handled separately.
|
||
|
|
||
|
Known module classes as in transcode 1.1.0:
|
||
|
|
||
|
demultiplex,
|
||
|
decode,
|
||
|
filter,
|
||
|
encode,
|
||
|
multiplex
|
||
|
|
||
|
Destroying a module is really simple. Just invoke the destruction
|
||
|
function using your factory and the module, and the latter will be
|
||
|
destroyed. But remember that real originating plugin will be
|
||
|
unloaded only with all spawned modules are destroyed.
|
||
|
In facts, destruction of last module triggers plugin
|
||
|
unloading. The factory can detect at any time if a given module is
|
||
|
the last one or not. You should'nt worry about this.
|
||
|
|
||
|
Take care to check the return code of tc_del_module, since it
|
||
|
triggers plugin unloading it can fail. Some debug messages are
|
||
|
sent to (real) users using tc_log*().
|
||
|
Future releases perhaps will add some detailed error codes than
|
||
|
actual ones, which just carries a "failed/succeeded" information.
|
||
|
|
||
|
|
||
|
3.5. TCModule
|
||
|
-------------
|
||
|
|
||
|
The reader might also take a look at tcmodule-data.h.
|
||
|
The `TCModule' data structure represent a module instance.
|
||
|
It is composed by two main components: the module class data,
|
||
|
comprehending function pointers to real module and capabilities
|
||
|
information, and the module instance section, private for each module.
|
||
|
|
||
|
You can see the declarations in tcmodule-data.h for more details.
|
||
|
Most of details are handled by NMS code, so you normally don't need
|
||
|
to access neither module class or module private instance data.
|
||
|
In facts, instance data should be accessed only by module code, and
|
||
|
should be opaque both for NMS and for client code.
|
||
|
|
||
|
It's safe to access (in read-only) the class data, and this is also
|
||
|
needed to effectively use a module, since function pointers to module
|
||
|
methods are embedded in class data. For this purpose a few commodities
|
||
|
macro are provided. Direct access is also possible.
|
||
|
The only 'critical' field in a class structure is the 'id' one.
|
||
|
This field is used internally by NMS (see code) and should not be even
|
||
|
considered by client code.
|
||
|
|
||
|
You can notice that both module instance data and module class data
|
||
|
have a 'id' field. These two fields are in fact independent, and both
|
||
|
must be considered opaque by client code.
|
||
|
|
||
|
|
||
|
3.6. Using modules
|
||
|
------------------
|
||
|
|
||
|
Usage of a module, if we want to ignore the internals and the gory details,
|
||
|
should be really easy and straightforwarded.
|
||
|
For each possibile module operation, there is a convenience (inline) function
|
||
|
for easier usage and to avoid clumsy module->operation(module, ... ) syntax.
|
||
|
|
||
|
The list of supported operations follows:
|
||
|
|
||
|
tc_module_configure(module, options, vob)
|
||
|
(re)configure a module, changing it's internal settings;
|
||
|
modules *requires* to be configure()d _explicitely_
|
||
|
before the usage.
|
||
|
|
||
|
tc_module_stop(module)
|
||
|
stop a module and prepare it for a new safe (re)configuration.
|
||
|
this means flushing all buffers, closing files and so on.
|
||
|
|
||
|
tc_module_inspect(module, param, *value)
|
||
|
query about the actual value of a given parameter.
|
||
|
|
||
|
tc_module_encode_video(module, inframe, outframe)
|
||
|
tc_module_encode_audio(module, inframe, outframe)
|
||
|
encode a give video or audio frame and store data in another one.
|
||
|
|
||
|
tc_module_decode_video(module, inframe, outframe)
|
||
|
tc_module_decode_audio(module, inframe, outframe)
|
||
|
decode a give video or audio frame and store data in another one.
|
||
|
|
||
|
tc_module_filter_video(module, vframe)
|
||
|
tc_module_filter_audio(module, aframe)
|
||
|
apply a filter in place to a video or audio frame.
|
||
|
|
||
|
tc_module_multiplex(module, vframe, aframe)
|
||
|
pack given encoded audio and video frame (both at once or just one)
|
||
|
|
||
|
tc_module_demultiplex(module, vframe, aframe)
|
||
|
unpack encoded audio and video frame (both or just one)
|
||
|
|
||
|
Just use any of above functions in your code. Do not forget to check the
|
||
|
return code. In the common case, return value of -1 means 'error',
|
||
|
and 0 means 'succesfull'.
|
||
|
|
||
|
A few special parameters exists for 'inspect':
|
||
|
|
||
|
for 'inspect':
|
||
|
* "all" option will force the module to return to calling environment
|
||
|
a representation of /all/ internal parameters, packed in a single
|
||
|
string. This string will be packed in the same format accepted by
|
||
|
module option string
|
||
|
* "help" option will force the module to return a textual, human readable
|
||
|
overview of the module, along with an explanation of name, value range
|
||
|
and meaning of accepted parameters. Special parameters will not be
|
||
|
present in this description.
|
||
|
|
||
|
|
||
|
4. Plugin API
|
||
|
---------------------------------------------------------------------------
|
||
|
|
||
|
The reader of this section is encouraged to take a look of documentation
|
||
|
of functions and data structures embedded into header files of NMS to
|
||
|
become familiar with the notions exposed here.
|
||
|
Interesting files:
|
||
|
|
||
|
libtc/tcmodule-plugin.h
|
||
|
libtc/tcmodule-data.h
|
||
|
libtc/tcmodule-info.h
|
||
|
|
||
|
|
||
|
4.1. What you need to use NMS (as a plugin writer)
|
||
|
--------------------------------------------------
|
||
|
|
||
|
Simply include the header file in your plugin source file (or in your main
|
||
|
plugin source file):
|
||
|
|
||
|
#include "tcmodule-plugin.h"
|
||
|
|
||
|
and you have access to all data structures, constants and functions
|
||
|
(in fact just one :) ) that you need. Of course, you must design your
|
||
|
plugin accordingly to NMS structure (covered later on this section and in
|
||
|
the following section).
|
||
|
Of course, your plugin must be compiled as shared object.
|
||
|
|
||
|
|
||
|
4.2. Example code
|
||
|
-----------------
|
||
|
|
||
|
You can take a look to filter/filter_null.c multiplex/multiplex_null.c
|
||
|
or encode/encode_null.c.
|
||
|
|
||
|
Future releases of this document will perhaps add more (pseudo)code
|
||
|
examples.
|
||
|
|
||
|
|
||
|
4.3. Structure of a NMS plugin
|
||
|
------------------------------
|
||
|
|
||
|
There is quite a few strict constraints about the structure of a NMS
|
||
|
plugin. Obviously, due to multiple-function-pointers structure, you
|
||
|
must provide a separate function for each method implemented.
|
||
|
This is intended to avoid the Single Huge Function Syndrome sometimes
|
||
|
found on old-style filters ;)
|
||
|
|
||
|
Is recommended to keep the biggest number of symbols on your plugin
|
||
|
as private (just use 'static' qualifier for functions and reduce
|
||
|
the usage of global variables, better to avoid it totally if it's
|
||
|
feasible -and usually it's-).
|
||
|
NMS has explicit support for module private data, so you should not
|
||
|
need to use static variables on your plugin.
|
||
|
Of course you can still use these, but _you_ must take care of
|
||
|
multi-instances problems and so on.
|
||
|
|
||
|
The only exception for above rule can be the capabilities data for
|
||
|
a plugin. This data is used only during the registration process
|
||
|
(see below for some other detail about this process), but is *copied*
|
||
|
into core in order to avoid dirty tricks. So you can just provide
|
||
|
a reference to some private variables. This is the preferred way
|
||
|
since it seems the most simple one.
|
||
|
|
||
|
To see a simple skeleton of a NMS plugin, take a look at
|
||
|
filter/filter_null.c or multiplex/multiplex_null.c or
|
||
|
encode/encode_null.c
|
||
|
|
||
|
|
||
|
4.4. The registration process
|
||
|
-----------------------------
|
||
|
|
||
|
The plugin registration process consist simply into a invocation
|
||
|
of tc_plugin_setup entry point. This function will return a
|
||
|
TCModuleClass filled by plugin with description informations
|
||
|
and with valid function pointers to operations implemented
|
||
|
by plugin.
|
||
|
|
||
|
Core will do some sanity checks on this descriptor returned
|
||
|
by plugin, and use the given informations to fill it's
|
||
|
own descriptor. Core WILL NOT change the informations provided
|
||
|
by a plugin, unless they are detected as incorrect. In this
|
||
|
case an error will be emitted (via tc_log*()) and more.
|
||
|
Core will also setup sensible fallback values for all informations,
|
||
|
or operations, not provided by a given plugin.
|
||
|
|
||
|
Once a plugin is registered, there is no way to change registered
|
||
|
data, nor to re-register or de-register itself.
|
||
|
|
||
|
|
||
|
4.5. The plugin entry point
|
||
|
---------------------------
|
||
|
|
||
|
(WRITEME)
|
||
|
|
||
|
4.6. Intialization and finalization of a module
|
||
|
------------------------------------------------
|
||
|
|
||
|
There is a couple of mandatory operations that a module must implement
|
||
|
still not covered in this document. Those operations are the 'init'
|
||
|
intialization operation and the 'fini' finalization operation.
|
||
|
Those operations WILL NOT be exported to client code, and are used
|
||
|
*only* trasparently by NMS code.
|
||
|
'init' operation take care of initializing the part of a module that
|
||
|
isn't changed by configure() operation and sets defaults.
|
||
|
'fini' operation must cleanup everything and release *all* resources
|
||
|
acquired by a module. Is the 'one and true' finalization routine, the
|
||
|
last that is executed during the module life.
|
||
|
|
||
|
|
||
|
4.7. Differences between module classes
|
||
|
---------------------------------------
|
||
|
|
||
|
(WRITEME)
|
||
|
|
||
|
|
||
|
5. Plugin-Writing-HOWTO
|
||
|
---------------------------------------------------------------------------
|
||
|
|
||
|
FIXME: WRITEME
|
||
|
|
||
|
|
||
|
6. Internal structure
|
||
|
---------------------------------------------------------------------------
|
||
|
|
||
|
This section holds sparse design notes about NMS current implementation.
|
||
|
The reader is encouraged to take a look to source files (libtc/tcmodule*.c)
|
||
|
to see the gory details.
|
||
|
|
||
|
|
||
|
6.1. Why the factory?
|
||
|
---------------------
|
||
|
|
||
|
The factory descriptor was make explicite for generality and extendability.
|
||
|
Having explicit factory descriptor make it possible to use more than
|
||
|
one factory at time, even if this will be unlikely useful.
|
||
|
There are some use cases for this on actual codebase at time of writing.
|
||
|
Anyway, it's trivial to force code to use just one factory using something
|
||
|
like:
|
||
|
|
||
|
/* some_tc_header.h */
|
||
|
|
||
|
extern TCModuleFactory main_factory;
|
||
|
|
||
|
#define tc_load_module(type, name) \
|
||
|
tc_new_module(main_factory, type, name)
|
||
|
#define tc_unload_module(type, name) \
|
||
|
tc_del_module(main_factory, mod)
|
||
|
|
||
|
|
||
|
6.2. About multithreading safeness
|
||
|
----------------------------------
|
||
|
|
||
|
Multiple thread CANNOT execute operations concurrently on the same factory
|
||
|
descriptor.
|
||
|
It is safe to execute concurrently operations if each module operate on
|
||
|
it's own descriptor. This means different threads can safely use different
|
||
|
TCModule, but using one TCModule, or one TCFactory by two or more threads
|
||
|
won't work.
|
||
|
|
||
|
|
||
|
6.3. On explicit reference counting
|
||
|
-----------------------------------
|
||
|
|
||
|
On linux systems, dlopen() manpage reports that dl code can trasparently
|
||
|
handle reference count of dlopen()ed modules, so there is no strict need
|
||
|
of explictely do reference counting and avoid multiple loading on NMS.
|
||
|
I don't know yet if this behaviour is portable.
|
||
|
Moreover, I don't still want to drop explicit reference count on NMS,
|
||
|
since it not complicate things too much and it can helps on accounting
|
||
|
and debug purposes. This can change in future releases, but this should
|
||
|
be a change totally transparent to client code.
|
||
|
|
||
|
|
||
|
6.4. Possibile API and ABI breakage
|
||
|
-----------------------------------
|
||
|
|
||
|
Needs a careful review and a bit of discussion on transcode-devel.
|
||
|
|
||
|
|
||
|
6.5. init VS configure, fini VS stop
|
||
|
------------------------------------
|
||
|
|
||
|
This section will higlight and summarize the differences between the
|
||
|
init/configure and the stop/fini couple.
|
||
|
|
||
|
init: ALWAYS executed BEFORE 'configure'.
|
||
|
Runs one and only one time during the life of a module.
|
||
|
configure: ALWAYS executed AFTER 'init'.
|
||
|
Can run one or more times during the life of a module.
|
||
|
Modules REQUIRES that configure is runned at least once.
|
||
|
It is possible that invokations of configures after the first
|
||
|
will be ignored by a given module.
|
||
|
|
||
|
fini: ALWAYS executed AFTER 'stop'.
|
||
|
Runs one and only one time during the life of a module.
|
||
|
it is possible (and usually happens) that fini invokes 'stop'.
|
||
|
stop: ALWAYS executed BEFORE 'fini'.
|
||
|
Can run zero or more times during the life of a module.
|
||
|
Modules REQUIRES that stop is runned before to be re-configure()d.
|
||
|
It is possible that this function will do not anything useful.
|
||
|
|
||
|
|
||
|
7. Final notes
|
||
|
---------------------------------------------------------------------------
|
||
|
|
||
|
send any comment to <fromani@gmail.com>. Thanks for reading this.
|
||
|
Corrections about english are welcome.
|
||
|
|
||
|
|
||
|
8. Appendix A: planned improvements in 1.2.0 and beyond
|
||
|
---------------------------------------------------------------------------
|
||
|
(without a particular order)
|
||
|
|
||
|
1. Generic init/fini functions. Most of them are boilerplate code and
|
||
|
there is no need to replicate them every time.
|
||
|
2. New filter operations with explicit destination argument:
|
||
|
|
||
|
int (*process_video)(TCModuleInstance self, vframe_list_t *src, vframe_list_t *dst);
|
||
|
int (*process_audio)(TCModuleInstance self, aframe_list_t *src, aframe_list_t *dst);
|
||
|
|
||
|
3. Add open/close functions to improve (de)multiplexors:
|
||
|
|
||
|
int (*open)(TCModuleInstance self, const char *name, uint32_t flags);
|
||
|
int (*close)(TCModuleInstance self);
|
||
|
|
||
|
4. Needs careful planning: subdivide modules in separate classes to
|
||
|
reduce function bloat.
|
||
|
5. Make modules arguments explicit and handled by core: that semplifies
|
||
|
modules, reduce duplication, adds sanity checks for free.
|
||
|
6. Related to above: overhaul or get rid of optstr* stuff.
|
||
|
7. More docs, more sample code.
|
||
|
8. Make explicit preferred (native?) colorspace for modules (the one for which
|
||
|
the module is designed about, so it provide bests results).
|
||
|
9. Improve (make explicit?) flush API in muxers.
|
||
|
10. better muxing API (using chunks?).
|
||
|
|
||
|
# EOF
|