Added KDE3 version of MLT

git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/libraries/mlt@1095634 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
v3.5.13-sru
tpearson 15 years ago
commit 40f8286642

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

@ -0,0 +1,58 @@
$Id: ChangeLog 1008 2007-07-15 01:19:30Z ddennedy $
USING svn log NOW
2007-04-09 Dan Dennedy <dan@dennedy.org>
Cleanup copyrights and attributions, and move Jean-Baptiste's services
to a new kdenlive module.
2007-03-30 Dan Dennedy <dan@dennedy.org>
Add support for sox 13.0.0.
2007-03-30 Jean-Baptiste Mardelle <jb@kdenlive.org>
Fix boxblur and wave filters license.
2007-03-29 Dan Dennedy <dan@dennedy.org>
Cleanup license declarations and remove dv1394d references.
Change registration of vmfx/mono to threshold to disambiguate with
core/mono.
2007-03-27 Dan Dennedy <dan@dennedy.org>
Fix ffmpeg swscale code enabled with mmx flags and fix --enable-swscale
in conjunction with --avformat-static.
2007-03-16 Dan Dennedy <dan@dennedy.org>
Added docs/policies.txt.
2007-02-19 Jean-Baptiste Mardelle <jb@kdenlive.org>
Blur and wave filters: fix typos and make functions static (patch from Stephane Fillod)
2007-02-18 Jean-Baptiste Mardelle <jb@kdenlive.org>
Add blur and wave filters from Leny Grisel
2007-02-07 Dan Dennedy <dan@dennedy.org>
Added ffmpeg libswscale support to avformat module (requires configure
option --avformat-swscale)
2006-12-07 Dan Dennedy <dan@dennedy.org
Applied patch from Stephane Fillod to make configure run with bash
since it uses bash-specific features. Also, patches headers to
C comments for pedantic compilation.
2006-09-28 Zachary Drew <zachary.drew@gmail.com>
applied audio frequency and audio channels initialization patch from Jean-Baptiste
2006-09-27 Zachary Drew <zachary.drew@gmail.com>
applied amd64 patch from gentoo folks to fix compilation of motion_est
on amd64 (thanks for the heads-up Jean-Michel)
2006-09-25 Dan Dennedy <dan@dennedy.org>
- src/modules/sdl/Makefile: fix compilation on some systems using
modular x.org.
2006-08-08 Dan Dennedy <dan@dennedy.org>
enhance producer_westley to parse Kino 0.9.1 SMIL (clock) time values.
2006-08-08 Dan Dennedy <dan@dennedy.org>
convert --avformat-cvs to svn and rename option as --avformat-svn (--avformat-cvs is an undocumented alias).

340
GPL

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

@ -0,0 +1,61 @@
SUBDIRS = src/framework \
src/inigo \
src/valerie \
src/miracle \
src/humperdink \
src/albino \
src/modules \
profiles
all clean:
list='$(SUBDIRS)'; \
for subdir in $$list; do \
$(MAKE) -s -C $$subdir depend || exit 1; \
$(MAKE) -C $$subdir $@ || exit 1; \
done
distclean:
rm mlt-config packages.dat; \
list='$(SUBDIRS)'; \
for subdir in $$list; do \
$(MAKE) -C $$subdir $@ || exit 1; \
done; \
rm config.mak;
dist-clean: distclean
include config.mak
install:
install -d "$(DESTDIR)$(prefix)/bin"
install -d "$(DESTDIR)$(prefix)/include"
install -d "$(DESTDIR)$(libdir)"
install -d "$(DESTDIR)$(libdir)/pkgconfig"
install -d "$(DESTDIR)$(prefix)/lib/mlt/modules"
install -d "$(DESTDIR)$(prefix)/share/mlt/modules"
install -c -m 755 mlt-config "$(DESTDIR)$(bindir)"
install -c -m 644 *.pc "$(DESTDIR)$(libdir)/pkgconfig"
install -m 644 packages.dat "$(DESTDIR)$(prefix)/share/mlt/"
list='$(SUBDIRS)'; \
for subdir in $$list; do \
$(MAKE) DESTDIR=$(DESTDIR) -C $$subdir $@ || exit 1; \
done; \
# if test -z "$(DESTDIR)"; then \
# /sbin/ldconfig || true; \
# fi
uninstall:
rm -f "$(DESTDIR)$(bindir)"/mlt-config
rm -f "$(DESTDIR)$(libdir)/pkgconfig/mlt-*.pc"
list='$(SUBDIRS)'; \
for subdir in $$list; do \
$(MAKE) DESTDIR=$(DESTDIR) -C $$subdir $@ || exit 1; \
done
rm -rf "$(DESTDIR)$(prefix)/include/mlt"
rm -rf "$(DESTDIR)$(prefix)/share/mlt"
dist:
[ -d "mlt-$(version)" ] && rm -rf "mlt-$(version)" || echo
svn export . "mlt-$(version)"
svn log > "mlt-$(version)/ChangeLog"
tar -cvzf "mlt-$(version).tar.gz" "mlt-$(version)"

@ -0,0 +1,65 @@
MLT/Miracle README
------------------
Sponsored by Ushodaya Enterprises Limited
Written by Charles Yates <charles.yates@pandora.be>
and Dan Dennedy <dan@dennedy.org>
MLT is a LGPL multimedia framework designed for television broadcasting,
and Miracle is a GPL multi-unit video playout server with realtime
effects.
This document provides a quick reference for the minimal configuration,
build and installation of MLT. See the docs directory for usage and
development details.
Configuration
-------------
Configuration is triggered by running:
./configure
More information on usage is found by running:
./configure --help
NB: This script must be run to register new services after a CVS checkout
or subsequent update.
Compilation
-----------
Once configured, it should be sufficient to run:
make
to compile the system.
Testing
-------
To execute the mlt tools without installation, or to test a new version
on a system with an already installed mlt version, you should run:
. setenv
NB: This applies to your current shell only and it assumes a bash or
regular bourne shell is in use.
Installation
------------
The install is triggered by running:
make install
More Information
----------------
For more detailed information, please refer to docs/install.txt.

@ -0,0 +1,2 @@
Wed Feb 24 12:10:50 CST 2010
./configure --enable-gpl --luma-compress --disable-mmx --enable-motion-est --avformat-shared=/usr --avformat-swscale --prefix=/opt/kde3 --with-extra-libs=/opt/kde3/lib --with-extra-includes=/opt/kde3/include/kde

@ -0,0 +1,217 @@
MLT Demo Notes
Before running the demo script, make sure you '. setenv' from the parent
directory. Also, please create clips clip1.dv, clip2.dv, clip3.dv, clip1.mpeg,
clip2.mpeg, clip3.mpeg, and music1.ogg. Please make sure clips are at least 500
frames duration.
These notes explain the the concepts presented in each demonstration and
what details to look for.
First, a note on consumers. When you start the script, the main menu asks
you to choose a consumer. A consumer is like a viewer, but it could also
write to a stream/file. The "SDL" consumer is the popular Simple DirectMedia
Layer audio and video output. The "Westley" consumer generates an XML
representation of the service network. That can be played directly due to the
westley producer plugin. See docs/westley.txt for more information. The
"MainConcept DV" consumer refers to the proprietary MLT plugin required to
use MLT with MainConcept DV, DVCPro, and MPEG codecs. "/dev/dv1394/0" refers
to a device file for transmitting DV over FireWire using the Linux dv1394 kernel
module. The "BlueFish444" consumer is another proprietary plugin to use
the BlueFish444 manufactured SDI video/audio output cards with MLT.
And now the demos...
All clips
Simply builds a playlist containing each video clip, and you can transport
between them using j and k keys.
Filter in/out
A video filter can be applied to a portion of a producer (clip, playlist,
or multitrack). This examples shows the greyscale filter.
Watermark
A graphic can overlay video in realtime with support for alpha channel.
This example uses a PNG file with an alpha channel. Distortion is explicitly
enabled here so the otherwise circular graphic is scaled to fill the
compositing region. By default, compositing honours the aspect ratio of the
overlay.
My name is...
Titles are very easy to composite in realtime. The titler uses Pango
with the FreeType2 rendering backend. This means it supports high
quality scalable font rendering with anti-aliasing, unicode (UTF-8),
and Pango markup capabilities. The compsiting here respects the aspect
ratio of the rendered title in the first two title pieces but distorts
the final one. This demo also shows the motion and scaling capabilities
of the compositor in conjunction with honouring aspect. The compositor
is doing field-based rendering. So, when displayed non-progressively
with SDL, you can see motion artifacts during animation.
A composite transition
The compositor also handles video over video as demonstrated in this
usage of the compositor to create a special transition. This demonstration
also crossfades the audio during the transition! Progressive rendering
is explicitly enabled on the compositor due to the poor results that
would otherwise occur due to scaling an interleaved video frame and moving
the video in a reverse direction horizontally.
Fade in and out
A simple series of transitions betwen 3 clips using dissolves and audio
crossfades. This is easy :-).
Clock in and out
Wipe transitions are very easy and highly extensible as they are generated
using a very convenient lookup table based upon the luma of an image.
This image can be a 16 bit PGM (grayscale bitmap) or the luma channel of
any video producer. A number of high quality wipes can be downloaded from
http://mlt.sf.net/. It also performs field rendering.
The second wipe demonstrates the ability to control the direction of the
wipe as well.
Obscure
A popular requirement in news production is to obscure a face, obscenity,
or trademarked logo. This demonstrates using a simple rectangular
obscure filter applied to a region of the image. The second example is more
advanced and shows using the "region" filter to select the image area and a
property of the region filter to "shape" the region using the alpha channel
of another image (circle.png) and another property to "filter" the region
using the obscure filter.
Audio Stuff
A music bed sound track can be mixed with a video. The sound track of the
video clip has a "floating" amplitude normalisation filter applied.
Typically, audio normalisation applies a constant gain factor across the
entire duration of an audio segment from a single source where the
gain factor is automatically determined by anaylsing the maximum "power"
or peak levels. However, in news production, a popular requirement is to
to dynamically boost the amplitude in soft areas and reduce the amplitude
in louder areas. Thus, the gain analysis is performed using a "sliding
window" approach. This example also applies a constant gain factor of
0.5 (50%) to the normalised audio of the video clip (to get a nicer
mix level).
Audio and Video Levels
Audio can be normalised by setting a target amplitude level in decibels.
A gamma curve can be applied to the luma channel of video.
Shadowed Title and Watermark
Two instances of the titler are used to create a shadow effect.
The aspect ratio of the watermark in this example is not distorted. Since
the original image is a circle with square pixels--a computer-generated
image--and ITU BT.601 video is not composed of square samples. Therefore,
the compositor normalises the pixel aspect ratio of the overlay to the
destination image, and the circular image remains circular on the analog
video output. Finally, a greyscale filter is applied to the watermark
while its opacity is set at 30%.
Station Promo into Story?
Here is fun demo that might show using a still graphic with some music
to introduce a show. A luma wipe with an audio crossfade transitions from
the show title or station promotional material.
Voiceover 2 clips with title
A common news production requirement to have a "voiceover" audio track
to a clip or even multiple clips as demonstrated here. Likewise, it is
common to place a title caption on the video at the same time! This
demo has a little fun with the titler at the sake of practicality :-)
The foreground of the title is transparent while the opacity of the
background is reduced to blend with the video. Meanwhile, the compositor
stretches the image to fill the bottom slice of the video--not suitable
for overscan displays ;-)
Also, pay close attention to the mixing levels of the audio tracks.
The audio of the video fades out as the voiceover track (just music
in this demo) fades in. Then, the voiceover remains mixed with the
ambient audio at a 60% level. Finally, the voiceover fades out smoothly
from the 60% level to nothing.
GJ-TTAvantika title
This demo requires a special TrueType font called Avantika. If you have the
font, register it with fontconfig using the fc-cache utility. This
demonstrates i18n capabilities of the titler and the alignment capabilities
of both the titler and the compositor. The titler centre aligns
the two lines of text, and the compositor centre aligns the title
horizontally on the frame.
Title over graphic
You can superimpose a title over a graphic over video! Also,
you can apply a luma wipe to the compositor!
Slideshow
This demo requires any number of JPEG images with the extension ".jpg"
in a subdirectory named "Scotland."
Bouncy, Bouncy
The "watermark" filter encapsulates the compositor, and you have full
control over the compositor properties. Who says a watermark can not
also be a video?!
Bouncy, Bouncy Ball
A variation on the above Bouncy, Bouncy demo that applies a shape, or
alpha producer, to the the compositing region.
Breaking News
This demonstrates layout capabilities of the compositor.
Squeeze Transitions
This demonstrates a distorting barndoor-like wipe.
J Cut
A J cut is an edit where the audio cuts before the video.
It gets its name from the way it looks on a NLE timeline user interface.
When the audio cuts over, it does an audio crossfade over the duration of
one frame. This makes the audio cut slightly less abrupt and avoids any
"click" due to mismatched sample levels at the edit point. The video edit
is a hard cut.
L Cut
An L cut is an edit where the video cuts before the audio.
It gets its name from the way it looks on a NLE timeline user interface.
This demo shows a very quick dissolve over 5 frames for a soft video cut.
Like the J Cut demo, an audio crossfade for the duration of one frame makes
an audio edit nearly instantaneous while being slightly softened and
avoiding aberrations.
Fade from/to black/silence
Of course, it is possible using MLT to fade from black on video and silence
on audio as well fade to black and silence.
Push wipe
A push wipe is a somewhat fancier transition than most standard wipes
because it involves motion. The new video clip "pushes" the old video
clip off one edge. If you can preview on an analog monitor you will notice
how smooth the motion is due to field-based rendering.
Ticker tape
A very minimal reverse crawling title neard the bottom of the screen.
The goal of the demo is show fluid motion of the field-based rendering of
the compositor when viewed on an analog monitor using a DV or BlueFish444
consumer. The demo also shows the potientional for using and extending the
existing set of services for a full blown news ticker implementation.

Binary file not shown.

@ -0,0 +1 @@
<svg width='300' height='300'><circle cx='150' cy='150' r='150' fill='white'/></svg>

After

Width:  |  Height:  |  Size: 85 B

@ -0,0 +1,12 @@
SDL Default sdl
SDL Half D1 sdl:360x288 rescale=nearest resize=1
SDL High Latency sdl buffer=12 rescale=none
SDL Progressive sdl progressive=1
Westley to Terminal westley
Westley to File westley:
MainConcept DV to /dev/dv1394/0 mcdv:/dev/dv1394/0 rescale=nearest buffer=25
libdv to /dev/dv1394/0 libdv:/dev/dv1394/0 rescale=nearest buffer=25
BlueFish444 PAL bluefish:1
BlueFish444 NTSC bluefish:1 standard=NTSC
BlueFish444 PAL Prog LL bluefish:1 progressive=1 buffer=1 frames=4
BlueFish444 NTSC Prog LL bluefish:1 standard=NTSC progressive=1 buffer=1 frames=4

@ -0,0 +1,106 @@
#!/bin/bash
function show_consumers( )
{
awk -F '\t' '{ printf( "%d. %s\n", ++ i, $1 ); }' < consumers.ini
}
function get_consumer( )
{
option=$1
[ "$option" != "" ] && [ $option -gt 0 ] && sed 's/\t\+/\t/g' < consumers.ini | cut -f 2 | head -n $option | tail -n -1
}
function show_menu( )
{
sed 's/\t\+/\t/g' < demo.ini |
awk -F '\t' '{ printf( "%2d. %-30.30s", ++ i, $2 ); if ( i % 2 == 0 ) printf( "\n" ); } END { if ( i % 2 == 1 ) printf( "\n" ); }'
}
function check_dependencies( )
{
option=$1
if [ $option -gt 0 ]
then
deps=`sed 's/\t\+/\t/g' < demo.ini | cut -f 3 | head -n $option | tail -n -1`
if [ "$deps" != "" ]
then
echo "$deps" |
tr ',' '\n' |
while read dep
do
ls $dep > /dev/null 2>&1
val=$?
[ $val != 0 ] && echo Failed to find $dep >&2 && echo $val
done
fi
echo 0
fi
}
function get_demo( )
{
option=$1
if [ $option -gt 0 ]
then
cut -f 1 demo.ini | head -n $option | tail -n -1
fi
}
while [ 1 ]
do
echo Select Consumer
echo
show_consumers
echo
echo 0. Exit
echo
echo -n "Option: "
read option
echo
[ "$option" == "0" ] && break
export MLT_CONSUMER=`get_consumer $option`
while [ "$option" != "0" -a "$MLT_CONSUMER" != "" ]
do
echo Choose Demo
echo
show_menu
echo
echo -n "Option: "
read option
echo
[ "$option" == "" ] && break
demo=`get_demo $option`
usable=`check_dependencies $option`
if [ "$usable" = "0" -a "$demo" != "" ]
then
if [ "$MLT_CONSUMER" == "westley:" ]
then export WESTLEY_CONSUMER="westley:$demo.westley"
bash $demo -consumer $WESTLEY_CONSUMER
inigo +$demo.txt out=100 $demo.westley $demo.westley -filter watermark:watermark1.png composite.fill=1 composite.geometry=85%,5%:10%x10%
elif [ "$MLT_CONSUMER" == "westley" ]
then bash $demo -consumer $MLT_CONSUMER | less
else bash $demo -consumer $MLT_CONSUMER
fi
elif [ "$usable" != "" ]
then
echo
echo Unable to locate suitable files for the demo - please provide them.
read pause
fi
stty sane
done
done

@ -0,0 +1,28 @@
mlt_all All clips clip*
mlt_effect_in_middle Filter in/out clip1.mpeg
mlt_watermark Watermark clip2.dv,watermark1.png
mlt_my_name_is My name is... clip3.dv
mlt_composite_transition A composite transition clip1.dv,clip2.mpeg
mlt_fade_in_and_out Fade in and out clip1.dv,clip2.mpeg,clip3.dv
mlt_clock_in_and_out Clock in and out clip2.dv,clip1.dv,clip3.mpeg
mlt_obscure Obscure clip2.mpeg,circle.png
mlt_audio_stuff Audio Stuff clip*.dv,music1.ogg
mlt_levels Audio and Video Levels clip*.dv
mlt_titleshadow_watermark Shadowed Title and Watermark clip3.dv
mlt_intro Station Promo into Story? watermark1.png,clip3.mpeg,music1.ogg
mlt_voiceover Voiceover 2 clips with title clip1.dv,clip2.mpeg,music1.ogg
mlt_avantika_title GJ-TTAvantika title pango.westley
mlt_title_over_gfx Title over graphic watermark1.png,clip1.dv
mlt_slideshow Slideshow Scotland
mlt_bouncy Bouncy, Bouncy clip1.dv,clip3.dv
mlt_bouncy_ball Bouncy, Bouncy Ball clip1.mpeg,clip3.mpeg,circle.png
mlt_news Breaking News clip1.dv,clip2.dv
mlt_squeeze Squeeze Transitions clip1.dv,clip2.dv,clip3.dv
mlt_squeeze_box Squeeze Box clip1.dv,clip2.dv,clip3.dv
mlt_jcut J Cut clip1.dv,clip2.dv
mlt_lcut L Cut clip1.dv,clip2.dv
mlt_fade_black Fade from/to black/silence clip3.mpeg
mlt_push Push wipe clip1.mpeg, clip2.mpeg
mlt_ticker Ticker tape clip1.dv
mlt_attributes Attributes clip1.dv
mlt_slideshow_black Composite slideshow Scotland

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<smil xmlns:smil2="http://www.w3.org/2001/SMIL20/Language">
<seq title="MLT" copyright="2004" abstract="foo man choo">
<video src="clip2.dv" clipBegin="171" clipEnd="450"/>
</seq>
<seq title="Demo">
<video src="clip2.dv" clipBegin="0" clipEnd="170"/>
</seq>
<seq>
<video src="clip1.dv" clipBegin="0" clipEnd="159"/>
<video src="clip3.dv" clipBegin="0" clipEnd="106"/>
</seq>
</smil>

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<!DOCTYPE westley SYSTEM "../src/modules/westley/westley.dtd" [
<!ENTITY name "Westley">
]>
<westley>
<producer id="producer0">
<property name="mlt_service">pango</property>
<property name="text">Hello &name;,
My name is Inigo Montoya.</property>
</producer>
</westley>

Binary file not shown.

@ -0,0 +1,3 @@
inigo \
clip* \
$*

@ -0,0 +1,7 @@
inigo clip1.dv \
meta.attr.location=1 meta.attr.location.markup="Location" \
meta.attr.exclusive=1 meta.attr.exclusive.markup="Exclusive" \
meta.attr.special=1 meta.attr.special.markup="Special" \
meta.attr.super=1 meta.attr.super.0="Line 1" meta.attr.super.1="Line 2" \
-filter data_show \
$*

@ -0,0 +1,6 @@
inigo \
clip*.dv \
-track music1.ogg \
-filter volume:0.5 normalise= track=0 \
-transition mix out=9999 a_track=0 b_track=1 \
$*

@ -0,0 +1,3 @@
inigo \
pango.westley \
$*

@ -0,0 +1,10 @@
inigo \
clip3.dv \
-filter \
watermark:clip1.dv \
composite.start=10%,10%:20%x20% \
composite.key[33]=30%,70%:25%x25% \
composite.key[66]=70%,30%:15%x15% \
composite.end=70%,70%:20%x20% \
composite.out=100 \
$*

@ -0,0 +1,14 @@
inigo \
clip3.dv \
-track \
clip1.dv \
-transition \
region:circle \
composite.geometry="10%,10%:20%x20%;33=30%,70%:25%x25%;66=70%,30%:15%x15%;-1=70%,70%:20%x20%" \
composite.out=100 \
composite.softness=0.1 \
a_track=0 \
b_track=1 \
in=0 \
out=5000 \
$*

@ -0,0 +1,7 @@
inigo \
clip2.dv in=100 out=174 -blank 99 clip3.dv in=100 \
-track \
-blank 49 clip3.mpeg in=100 out=249 \
-transition luma:luma1.pgm softness=0.5 in=50 out=74 a_track=0 b_track=1 \
-transition luma:luma1.pgm softness=0.2 in=175 out=199 a_track=0 b_track=1 reverse=1 \
$*

@ -0,0 +1,7 @@
inigo \
clip1.dv out=74 \
-track \
-blank 49 clip2.mpeg \
-transition composite:57%,10%:33%x33% end=0%,0%:100%x100% progressive=1 distort=true in=50 out=74 a_track=0 b_track=1 \
-transition mix:-1 in=50 out=74 a_track=0 b_track=1 \
$*

@ -0,0 +1,4 @@
inigo \
clip1.mpeg in=100 out=500 \
-filter greyscale in=100 out=199 \
$*

@ -0,0 +1,9 @@
inigo \
colour:black out=199 \
-track \
clip3.mpeg in=100 out=299 \
-transition luma in=0 out=49 a_track=0 b_track=1 \
-transition luma in=150 out=199 a_track=0 b_track=1 reverse=1 \
-filter volume in=0 out=49 track=1 gain=0 end=1.0 \
-filter volume in=150 out=199 track=1 gain=1.0 end=0 \
$*

@ -0,0 +1,9 @@
inigo \
clip1.dv out=74 -blank 99 clip3.dv in=25 \
-track \
-blank 49 clip2.mpeg out=149 \
-transition luma in=50 out=74 a_track=0 b_track=1 \
-transition luma in=175 out=199 a_track=0 b_track=1 reverse=1 \
-transition mix:-1 in=50 out=74 a_track=0 b_track=1 \
-transition mix:-1 in=175 out=199 a_track=0 b_track=1 reverse=1 \
$*

@ -0,0 +1,9 @@
inigo \
music1.ogg in=100 out=224 \
-track \
watermark1.png out=124 \
clip3.mpeg \
-mix 25 \
-mixer luma resource=luma1.pgm softness=0.2 \
-transition mix:-1 in=100 out=124 \
$*

@ -0,0 +1,10 @@
inigo \
-blank 49 \
clip2.dv in=100 \
-track \
clip1.dv out=99 \
-transition \
mix start=0 end=1 in=49 out=50 a_track=1 b_track=0 \
-transition \
mix:1 in=51 out=99 a_track=1 b_track=0 \
$*

@ -0,0 +1,12 @@
inigo \
clip1.dv out=100 \
-track \
-blank 49 \
clip2.dv in=100 \
-transition \
luma in=50 out=55 a_track=0 b_track=1 \
-transition \
mix:1 in=50 out=98 a_track=1 b_track=0 \
-transition \
mix start=1 end=0 in=99 out=100 a_track=1 b_track=0 \
$*

@ -0,0 +1,5 @@
inigo \
*.dv \
-filter gamma:1.5 \
-filter volume normalise=-20db \
$*

@ -0,0 +1,10 @@
inigo \
clip3.dv \
-track \
"+My name is Inigo Montoya.txt" out=99 -blank 49 "+Prepare to die!.txt" out=99 \
-track \
-blank 74 "+You killed my father.txt" out=74 \
-transition composite:50%,20%:5%x4% end=10%,20%:80%x12% distort=1 halign=centre valign=centre in=0 out=99 a_track=0 b_track=1 \
-transition composite:0%,70%:100%x10% end=100%,70%:100%x10% in=75 out=149 a_track=0 b_track=2 \
-transition composite:25%,25%:50%x50%! in=150 out=249 a_track=0 b_track=1 \
$*

@ -0,0 +1,18 @@
inigo \
colour:black out=199 \
-track \
clip1.dv in=0 out=0 -repeat 99 clip1.dv \
-track \
clip2.dv out=199 \
-track \
pango: text=" Breaking News
MLT Rocks India" bgcolour=0xff000080 out=149 \
pango: text=" Breaking News
MLT Rocks the World" bgcolour=0xff000080 out=349 \
-transition mix:0.5 always_active=1 a_track=0 b_track=2 \
-transition composite geometry=50%,15%:37.5%x40% a_track=0 b_track=1 in=0 out=174 \
-transition composite geometry=10%,15%:37.5%x40% a_track=0 b_track=2 in=0 out=199 \
-transition composite geometry="50%,15%:37.540%x40%;-1=0%,0%:100%x100%" a_track=0 b_track=1 in=174 out=199 distort=1 \
-transition composite geometry=10%,65%:90%x20% a_track=0 b_track=3 in=0 out=199 \
-transition composite geometry=10%,65%:90%x20% a_track=1 b_track=3 in=200 out=499 \
$*

@ -0,0 +1,5 @@
inigo \
clip2.mpeg \
-filter obscure:25%,25%:25%x25%:10x10 in=0 out=68 \
-filter region:circle.png filter=obscure composite.start=55%,25%:12%x50% in=68 out=200 \
$*

@ -0,0 +1,18 @@
inigo \
-blank 49 colour:black out=25 -blank 999 \
-track \
clip3.dv in=200 out=275 \
-track \
-blank 49 \
clip2.dv in=200 \
-transition \
composite in=50 out=75 a_track=0 b_track=1 \
start=0,0:100%x100%:100 \
end=100%,0:100%x100%:100 \
-transition \
composite in=50 out=75 a_track=0 b_track=2 \
start=-100%,0:100%x100%:100 \
end=0,0:100%x100%:100 \
-transition \
mix:-1 in=50 out=75 a_track=1 b_track=2 \
$*

@ -0,0 +1,4 @@
inigo \
Scotland/.all.jpg ttl=75 \
-filter luma:luma1.pgm luma.softness=0.1 luma.invert=0 \
$*

@ -0,0 +1,3 @@
inigo Scotland/.all.jpg ttl=100 \
-filter watermark:colour:black reverse=1 composite.geometry="15%,15%:10%,10%;0.1625=0,0:100%x100%;-.1625=;-1=70%,70%:10%x10%" composite.mirror_off=1 composite.cycle=100 composite.fill=1 composite.valign=c composite.halign=c \
$*

@ -0,0 +1,9 @@
inigo \
clip1.dv out=124 clip2.dv out=149 clip3.dv in=75 out=224 clip1.dv \
-track \
-blank 99 colour:black out=49 -blank 99 colour:black out=49 -blank 99 colour:black out=49 \
-group progressive=1 distort=1 \
-transition composite geometry="0%,0%:100%x100%;25=50%,0%:5%x100%;-1=0%,0%:100%x100%" a_track=1 b_track=0 in=100 out=149 \
-transition composite geometry="0%,0%:100%x100%;25=0%,50%:100%x5%;-1=0%,0%:100%x100%" a_track=1 b_track=0 in=250 out=299 \
-transition composite geometry="0%,0%:100%x100%;25=100%,0%:5%x100%;-1=0%,0%:100%x100%" a_track=1 b_track=0 in=400 out=449 \
$*

@ -0,0 +1,9 @@
inigo \
clip1.dv out=124 clip2.dv out=149 clip3.dv in=75 out=224 clip1.dv \
-track \
-blank 99 colour:black out=49 -blank 99 colour:black out=49 -blank 99 colour:black out=49 \
-group progressive=1 \
-transition composite:0%,0%:100%x100% key[25]=50%,0%:5%x100% end=0%,0%:100%x100% a_track=1 b_track=0 in=100 out=149 \
-transition composite:0%,0%:100%x100% key[25]=0%,50%:100%x5% end=0%,0%:100%x100% a_track=1 b_track=0 in=250 out=299 \
-transition composite:0%,0%:100%x100% key[25]=100%,0%:5%x100% end=0%,0%:100%x100% a_track=1 b_track=0 in=400 out=449 \
$*

@ -0,0 +1,15 @@
inigo \
clip1.dv out=299 \
-track \
colour:black out=299 \
-track \
"+The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog..txt" \
out=299 \
-transition \
composite a_track=0 b_track=1 out=299 distort=1 \
start=0,70%:100%x64:100 \
-transition \
composite a_track=0 b_track=2 out=299 titles=1 \
start=100%,70%:999%x20% \
end=-299%,70%:999%x20% \
$*

@ -0,0 +1,25 @@
inigo \
watermark1.png out=9999 \
-track \
"+title over gfx.txt" fgcolour=0x000000ff \
-track \
clip1.dv \
-transition \
composite start=30%,20%:40%x60% \
in=50 \
out=199 \
a_track=0 \
b_track=1 \
distort=1 \
-transition \
composite:0%,75%:100%x20%:0 \
in=50 \
out=199 \
a_track=2 \
b_track=0 \
key[24]=0%,75%:100%x20%:100 \
key[-25]=0%,75%:100%x20%:100 \
luma=luma1.pgm \
end=0%,75%:100%x20%:0 \
distort=1 \
$*

@ -0,0 +1,10 @@
inigo \
"+hello~world.txt" align=1 out=1000 \
-track "+hello~world.txt" align=1 out=1000 fgcolour=0x000000ff \
-track watermark1.png out=1000 \
-track clip3.dv \
-filter greyscale track=2 \
-transition composite:21%,11%:100%x100%:50 end=61%,41%:100%x100% out=99 a_track=3 b_track=1 \
-transition composite:20%,10%:100%x100% end=60%,40%:100%x100% out=99 a_track=3 b_track=0 \
-transition composite:85%,80%:10%x10%:30 out=1000 a_track=3 b_track=2 \
$*

@ -0,0 +1,36 @@
inigo \
"+voice over demo.txt" \
font="Sans Bold 72" \
fgcolour=0x00000000 \
bgcolour=0xff9933aa \
pad=10 \
-track music1.ogg \
-track clip1.dv out=149 clip2.mpeg \
-transition \
mix:0.0 \
end=0.6 \
in=75 \
out=99 \
a_track=2 \
b_track=1 \
-transition \
mix:0.6 \
in=100 \
out=299 \
a_track=2 \
b_track=1 \
-transition \
mix:0.6 \
end=0.0 \
in=300 \
out=324 \
a_track=2 \
b_track=1 \
-transition \
composite:0%,80%:100%x20% \
distort=1 \
in=100 \
out=299 \
a_track=2 \
b_track=0 \
$*

@ -0,0 +1,6 @@
inigo \
clip2.dv out=1000 \
-track \
watermark1.png out=1000 \
-transition composite fill=1 in=0 out=1000 a_track=0 b_track=1 geometry=85%,5%:10%x10% \
$*

@ -0,0 +1,51 @@
<playlist>
<entry>
<multitrack>
<playlist>
<producer id="foo" in="100" out="149">
<property name="resource">clip2.mpeg</property>
</producer>
<blank length="25"/>
<entry producer="foo" in="10" out="59"/>
</playlist>
<playlist>
<blank length="25"/>
<producer id="bar" in="100" out="149">
<property name="resource">clip3.mpeg</property>
</producer>
<entry out="99" producer="bar"/>
</playlist>
</multitrack>
<filter track="0">
<property name="mlt_service">greyscale</property>
</filter>
<transition in="25" out="49" a_track="0" b_track="1">
<property name="mlt_service">luma</property>
</transition>
<transition in="75" out="99" a_track="0" b_track="1" mlt_service="luma">
<property name="reverse" value="1"/>
</transition>
</entry>
<entry>
<multitrack>
<playlist>
<entry producer="foo" in="100" out="149"/>
<blank length="25"/>
<entry producer="foo" in="10" out="59"/>
</playlist>
<playlist>
<blank length="25"/>
<entry producer="bar" in="100" out="149"/>
<entry out="99" producer="bar"/>
</playlist>
</multitrack>
<transition in="25" out="49" a_track="0" b_track="1">
<property name="mlt_service">luma</property>
</transition>
<transition in="75" out="99" a_track="0" b_track="1" mlt_service="luma">
<property name="reverse">1</property>
</transition>
</entry>
</playlist>

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<westley>
<producer id="video">
<property name="resource">clip1.dv</property>
</producer>
<producer id="title">
<property name="mlt_service">pango</property>
<property name="resource">+.txt</property>
<property name="font">GJ-TTAvantika 36</property>
<property name="align">1</property>
<property name="fgcolour">0xffffddff</property>
<property name="bgcolour">0x8c101080</property>
<property name="pad">8</property>
<property name="text"><![CDATA[ʾúlÉäºÉÒ qàö»ÉÉ<
HíÉà~ÉÒ+àeôÒ`ò­÷ +y«ÉKÉ §ÉÉWð~É]]></property>
</producer>
<tractor>
<multitrack>
<track producer="title"/>
<track producer="video"/>
</multitrack>
<transition in="0" out="150">
<property name="mlt_service">composite</property>
<property name="a_track">1</property>
<property name="b_track">0</property>
<property name="start">-70%,65%:100%x35%:0</property>
<property name="key[25]">0,65%:100%x35%:100</property>
<property name="key[125]">0,65%:100%x35%:100</property>
<property name="end">0,65%:100%x35%:0</property>
<property name="halign">centre</property>
<property name="valign">centre</property>
</transition>
</tractor>
</westley>

@ -0,0 +1,50 @@
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000303 Stylable//EN" "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd" [
<!ENTITY st0 "fill-rule:evenodd;clip-rule:evenodd;fill:url(#aigrd1);stroke:none;">
<!ENTITY st1 "stroke-width:0.8755;">
<!ENTITY st2 "fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;stroke:none;">
<!ENTITY st3 "fill:none;stroke:none;">
<!ENTITY st4 "fill-rule:evenodd;clip-rule:evenodd;fill:url(#aigrd2);stroke:none;">
<!ENTITY st5 "fill-rule:evenodd;clip-rule:evenodd;stroke:none;">
<!ENTITY st6 "fill-rule:nonzero;clip-rule:nonzero;stroke:#000000;stroke-miterlimit:4;">
]>
<westley>
<playlist>
<entry>
<producer out="99" length="99">
<property name="mlt_service">pixbuf</property>
<property name="resource">
<!-- Generator: Adobe Illustrator 9.0, SVG Export Plug-In -->
<svg width="24pt" height="24pt" viewBox="0 0 24 24" xml:space="preserve">
<g id="Layer_x0020_2" style="&st6;">
<path style="&st1;" d="M1,12.1c0,6.1,5,11.1,11.1,11.1c6.1,0,11.1-5,11.1-11.1c0-6.1-5-11.1-11.1-11.1C5.9,1.1,1,6,1,12.1z"/>
<radialGradient id="aigrd1" cx="8.7681" cy="8.0513" r="13.7645" fx="8.7681" fy="8.0513" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FED182"/>
<stop offset="0.2809" style="stop-color:#FFB310"/>
<stop offset="1" style="stop-color:#996E04"/>
</radialGradient>
<path style="&st0;" d="M21.3,12c0,5.2-4.2,9.4-9.4,9.4c-5.2,0-9.4-4.2-9.4-9.4c0-5.2,4.2-9.4,9.4-9.4c5.2,0,9.4,4.2,9.4,9.4z"/>
</g>
<g id="Layer_x0020_3" style="&st6;">
<path style="&st5;" d="M16.4,7.2c-0.5,0.1-0.9,0.3-1.2,0.7c0,0-3,4.2-4.1,5.6c-0.9-0.9-2.5-2.5-2.5-2.5c-0.3-0.3-0.8-0.5-1.3-0.5c-0.5,0-0.9,0.2-1.3,0.5c-0.7,0.7-0.7,1.8,0,2.5l3.9,3.9c0.4,0.4,0.9,0.5,1.4,0.5c0.5,0,1-0.3,1.3-0.7l5.4-7.1
c0.6-0.8,0.5-1.9-0.3-2.5c-0.4-0.3-0.8-0.4-1.3-0.4z"/>
<path style="&st2;" d="M16.6,7.4c-0.5,0.1-0.9,0.3-1.2,0.7c0,0-3,4.2-4.1,5.6c-0.9-0.9-2.5-2.5-2.5-2.5c-0.3-0.3-0.8-0.5-1.3-0.5c-0.5,0-0.9,0.2-1.3,0.5c-0.7,0.7-0.7,1.8,0,2.5l3.9,3.9c0.4,0.4,0.9,0.5,1.4,0.5c0.5,0,1-0.3,1.3-0.7l5.4-7.1
c0.6-0.8,0.5-1.9-0.3-2.5c-0.4-0.3-0.8-0.4-1.3-0.4z"/>
<radialGradient id="aigrd2" cx="8.6733" cy="8.6187" r="11.0872" fx="8.6733" fy="8.6187" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#F0E1BD"/>
</radialGradient>
<path style="&st4;" d="M16.5,7.3c-0.5,0.1-0.9,0.3-1.2,0.7c0,0-3,4.2-4.1,5.6C10.3,12.6,8.6,11,8.6,11c-0.3-0.3-0.8-0.5-1.3-0.5c-0.5,0-0.9,0.2-1.3,0.5c-0.7,0.7-0.7,1.8,0,2.5l3.9,3.9c0.4,0.4,0.9,0.5,1.4,0.5c0.5,0,1-0.3,1.3-0.7l5.4-7.1
c0.6-0.8,0.5-1.9-0.3-2.5c-0.4-0.3-0.8-0.4-1.3-0.4z"/>
</g>
<g id="Layer_x0020_4" style="&st6;">
<path style="&st3;" d="M24,24H0V0h24v24z"/>
</g>
</svg>
</property>
</producer>
</entry>
</playlist>
</westley>

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

@ -0,0 +1 @@
Review and documentation update. The review will yield a TODO with more tasks.

@ -0,0 +1,339 @@
Miracle Control Protocol (DVCP) Reference Documentation
Copyright (C) 2004 Ushodaya Enterprised Limited
Author: Dan Dennedy <dan@dennedy.org>
Last Revision: 2004-03-20
General Format
--------------
DVCP is an ASCII-based request/response TCP protocol much like FTP and
inspired by the SGI MVCP (Multiport Video Computer Protocol). Each
command is three to eight characters long followed by zero or more
arguments. Every item (command or argument) in the request is delimited
by a space and terminated with a new line. Arguments that contain spaces
must be surrounded by double quotation marks. The new line must contain
a line feed optionally preceeded by a carriage return. There are no
request header lines or body.
Response Codes
--------------
Responses consist of a numeric result code followed by a space folowed
by a brief textual description of the result. No quoting is applied to
descriptions regardless if it contains spaces. The result codes are
grouped by the hundreds into general categories of responses. Anything
in the 200-299 range is considered a success and anything 300 and above
is an error or exception. Most responses do not contain a body except
some of the success results that report information and sometimes the
500 Server Error returns specific information.
A 200 result code contains no body.
A 201 result code contains one or more lines in the body, and an empty
line terminates the response.
A 202 result code contains only a single response line in the body.
Errors in the 400 range indicate a normally handled error where the
command could not perform its action due to protocol syntax errors or
problems with validation of one or more of the arguments. This usually
indicates that the client is responsible for performing an illegal
request.
Errors in the 500 range indicate a server error or exception.
The following is a list of response codes and their descriptions:
200 OK
201 OK
202 OK
400 Unknown command
401 Operation timed out
402 Argument missing
403 Unit not found
404 Failed to locate or open clip
405 Argument value out of range
500 Server Error
Establishing a Connection
-------------------------
One can connect to the miracle server using telnet or a custom client,
preferrably one developed using the valerie client API. The default port
is 5250. Connections can be broken at will or use the BYE command to
request the server to terminate the connection.
General Command Information
---------------------------
All commands are case insensitive. Arguments may or may not be case
sensitive. There are two categories of commands: global and unit. Global
commands operate at the server level. Unit commands address a specific
unit. miracle is a multi-unit system. Units are named as U? where ?
is the unit number, for example, U0. As units are added to the server,
the unit number increases; the first unit is U0.
The command HELP lists all commands known to the server with a brief
description of their purpose and arguments. Most commands take zero or
one argument outside of the unit name. Sometimes an argument is
optional, and an optional argument always follows required arguments.
All units command required a unit name argument.
{} = required argument
[] = optional argument
() = one of a set of pre-defined values
Global Commands
---------------
HELP
List the commands and their brief description.
BYE
Close the connection.
SHUTDOWN
Shutdown the server and all client connections.
SET {key=value}
Set a global server configuration property.
Currently, the only planned key is "root" to set the base directory
path for the CLS and LOAD commands. The default root value is /.
GET {key}
Get the current value of a configuration property.
The value is returned by itself in the body of the response.
CLS {path}
List the clips and subdirectories at {path} on the server.
Only subdirectories, non-hidden regular files, symbolic links, and NFS
shares are supported.
The response body contains one line per item.
The name of the subdirectory/file is always surrounded by double
quotation marks in case it contains spaces.
Subdirectories are listed before files and have a trailing / in their
name.
File entries have a size value in bytes in the second column position.
RUN {file}
Process the commands in a file located on the server.
Commands are executed one after the other with no delay until the end
of file is reached or a command returns a response code not in the 200
range.
The response body contains each command sent along with its arguments,
followed by each command's response status code and response body.
STATUS
Responds with the output of USTA for each unit and accepts no further
input. Each time the state of the unit changes, a new row is returned by
the server containing the state of the unit.
Unit Management
The following global commands manage the DV units within the server.
Currently there is a maximum of four units, and units can not be
removed. Each unit may be in an online or offline state. Offline units
can not be used, and any unit commands issued against an offline unit
results in a 403 response.
NLS
* NOT IMPLEMENTED IN MIRACLE YET *
UADD mlt-consumer[:argument]
Add a unit based upon the mlt-consumer id and optional constructor
argument.
If the consumer is not found, then it still added but in an
offline manner. Later, by adding the device to the bus, the unit will
automatically become online.
The response body contains the name of the new unit: U0, U1, U2, or U3.
Channel is an optional setting.
ULS
List the units.
The response body contains a space-delimited row for each unit in the
server containing the following columns:
- unit name (one of U0, U1, U2, or U3)
- mlt-consumer[:argument] from uadd
- 1394 node GUID (defunt - always 0 with miracle for now)
- online flag (1 = online, 0 = offline)
SHUTDOWN
Shutdown the server.
Unit Commands
-------------
The first argument of any unit command is the unit name (U0 - U3). A
unit must be loaded with a file before it can play anything. A "clip"
refers to the presence of a file loaded into the unit. A clip can
contain an in and out point to set the playback region. The default in
point is 0, and the default out point is the number of frames in the
file minus one. Therefore, all frame positions are zero-based.
USET {unit} {key=value}
Set a unit's configuration property.
Key is one of the following: eof, points.
Property "eof" determines what the playback engine does when it reaches
the end of a clip. The eof property takes one of the following values:
stop, loop, continue or pause. The default is pause.
Property "points" determines whether the playback engine restricts the
playback region to the in and out points. It takes one of the following
values: use, ignore.
UGET {unit} {key}
Get a unit's configuration property.
Key is one of the following: eof, points.
The response body contains only the key's value. See USET for information
about each property.
LIST {unit}
List the clips associated to the unit.
The response body consists of two sections - the first section is a single row
containing the generation number of the playlist associated to the unit (an
integer starting from 0 which is incremented on each action which changes the
playlist). The second sections contais a space-delimited row for each clip in the
units playlistcontaining the following columns:
- clip index (starts from 0)
- file name
- in point
- out point
- real length of the files
- calculated length of file
When USET points=use is specified (default), the calculated size is (out-in)+1.
When points are ignored, the real length of the file is returned.
LOAD {unit} {filename} [in out]
Load a clip into the unit.
Optionally set the in and out points to the specified absolute frame numbers.
Sets the current position to the first frame in the clip.
Preface the filename with '!' to tell the disk reader thread to remove only
duplicate frames from the tail of its buffer queue (from a previously loaded
and playing clip). Otherwise, miracle flushes all of its buffers upon LOAD
to make the effect of LOAD instantaneous. The LOAD !, USET eof=pause, and
extended USTA information can be used for client-side playlists (see the
demo programs).
APND {unit} {filename} [in out]
Append a clip onto the unit's playlist.
Optionally set the in and out points to the specified absolute frame numbers.
INSERT {unit} {filename} [ [+|-]clip [ in out ] ]
Insert a clip into the units playlist at the specified clip index or relative
to the currently playing clip index.
REMOVE {unit} [ [+|-]clip ]
Removes a clip from the specified clip index or position relative to the
currently playing clip index.
CLEAN {unit}
Removes all by the playing clip.
WIPE {unit}
Removes all clips before the playing clip.
MOVE {unit} [+|-]clip [ [+|-]clip ]
Move a clip in the playlist to position specified or position relative to the
currently playing clip.
PLAY {unit} [speed]
Commence unit playback from the current position.
The default speed is 100% if not specified.
Speed is represented as a percentage value multiplied by 10. Therefore
the default playback speed is 1000 (1X or 100%), 2X is 2000.
Negative speed values play in reverse.
STOP {unit}
Terminate the unit playback resulting in no video being sent.
PAUSE {unit}
Pause the unit playback causing the current frame position to he held
indefinitely.
REW {unit}
Rewind the unit.
If the unit it playing, then REW sets the playback speed to -2000
(200%).
If the unit is stopped, then the frame position is reset to the first
frame. First frame depends upon the "points" unit configuration property
and whether an in point has been established for the clip using the SIN
command.
Set the currently loaded clip's in point.
Frame is zero-based and absolute. It is not dependent upon the clip's
current in point.
A frame-number of -1, resets the in point to 0.
FF {unit}
Fast forward the unit.
If the unit it playing, then FF sets the playback speed to 2000 (200%
in reverse).
If the unit is stopped, then the frame position is reset to the first
frame. First frame depends upon the "points" unit configuration property
and whether an in point has been established for the clip using the SIN
command.
STEP {unit} {number-of-frames}
Adjust the current frame position by the number of frames specified.
Number-of-frames can accept positive or negative values.
GOTO {unit} {frame-number} [ [+|-]clip ]
Set the current frame position to frame-number.
Frame-number is zero-based and absolute within the clip, which means it is
relative to the file beginning and not the clip in point.
It does not alter the playback status of the unit.
SIN {unit} {frame-number} [ [+|-]clip ]
Set the currently loaded clip's in point.
The in point is the logical starting frame of the clip.
Frame is zero-based and absolute. It is not dependent upon the clip's
current in point.
A frame-number of -1, resets the in point to 0.
SOUT {unit} {frame-number} [ [+|-]clip ]
Set the currently loaded clip's out point.
The out point is the logical last frame of the clip.
Frame is zero-based and absolute. It is not dependent upon the clip's
current out point.
A frame-number of -1, resets the out point to the number of frames in
the file minus 1.
USTA {unit}
Get the unit status report.
The response body contains the following fields delimited by spaces:
- unit number: U0, U1, U2, or U3 without the "U" prefix
- mode: (offline|not_loaded|playing|stopped|paused|disconnected|unknown)
"unknown" means the unit has not been added
"disconnected" means the server has closed the connection to the client.
- current clip name: filename
- current position: in absolute frame number units
- speed: playback rate in (percent * 10)
- fps: frames-per-second of loaded clip
- current in-point: starting frame number
- current out-point: ending frame number
- length of the clip
- buffer tail clip name: filename
- buffer tail position: in absolute frame number units
- buffer tail in-point: starting frame number
- buffer tail out-point: ending frame number
- buffer tail length: length of clip in buffer tail
- seekable flag: indicates if the current clip is seekable (relates to head)
- playlist generation number
- current clip index (relates to head)
The status contains information based not only on the current frame being
output (current above) but also based upon the most recent frame read by
the disk reader thread and added to the tail of the input buffer queue
(buffer tail above).
XFER {unit} {target-unit}
Transfer the unit's clip to the target unit.
The clip inherently includes the in- and out-point information.
The target unit's "points" configuration property is set to "use."

File diff suppressed because it is too large Load Diff

@ -0,0 +1,378 @@
Inigo Documentation
Copyright (C) 2004 Ushodaya Enterprised Limited
Author: Charles Yates <charles.yates@pandora.be>
Last Revision: 2004-03-20
INIGO
-----
Preamble:
inigo was developed as a test tool for the MLT framework. It can be thought
of as a powerful, if somewhat obscure, multitrack command line oriented
video editor.
The following details the usage of the tool and as a result, provides a lot
of insight into the workings of the MLT framework.
Usage:
inigo [ -group [ name=value ]* ]
[ -consumer id[:arg] [ name=value ]* ]
[ -filter filter[:arg] [ name=value ] * ]
[ -attach filter[:arg] [ name=value ] * ]
[ -mix length [ -mixer transition ]* ]
[ -transition id[:arg] [ name=value ] * ]
[ -blank frames ]
[ -track ]
[ -split relative-frame ]
[ -join clips ]
[ -repeat times ]
[ producer [ name=value ] * ]+
General rules:
1. Order is incredibly important;
2. Error checking on command line parsing is weak;
3. Please refer to services.txt for details on services available;
4. The MLT framework, from which inigo has inherited its naming convention,
is very mlt-centric. Producers produce MLT frame objects and consumers
consume MLT frame objects. The distinction is important - a DV producer
does not produce DV, it produces MLT frames from a DV source, and similarly
a DV consumer does not consume DV, it consumes MLT frames and produces DV
frames.
Terminology:
'Producers' typically refer to files but may also indicate devices (such as
dv1394 input or video4linux). Hence, the more generic term is used [the more
generic usage is out of scope for now...].
'Filters' are frame modifiers - they always guarantee that for every frame
they receive, they output *precisely* one frame. Never more, never less,
ever. Nothing says that a filter cannot generate frames though
'Transitions' collect frames from two tracks (a and b) and output 1
modified frame on their 'a track', and 1 unmodified frame on their 'b track'.
Never more, never less, ever.
'Consumers' collect frames from a producer, do something with them and
destroy them.
Collectively, these are known as 'services'.
All services have 'properties' associated to them. These are typically
defaulted or evaluated and may be overriden on a case by case basis.
All services except consumers obey in and out properties.
Consumers have no say in the flow of frames [though they may give the
illusion that they do]. They get frames from a connected producer, use them,
destroy them and get more.
Basics:
To play a file with the default SDL PAL consumer, usage is:
$ inigo file
Note that 'file' can be anything that inigo has a known 'producer' mapping
for (so this can be anything from .dv to .txt).
You can also specify the producer directly, for example:
$ inigo avformat:file.mpeg
Would force the direct use of avformat for loading the file.
Properties:
Properties can be assigned to the producer by adding additional name=value
pairs after the producer:
$ inigo file in=50 out=100 something="something else"
Note that while some properties have meaning to all producers (for example:
in, out and length are guaranteed to be valid for all, though typically,
length is determined automatically), the validity of others are dependent on
the producer - however, properties will always be assigned and silently
ignored if they won't be used.
Multiple Files:
Multiple files of different types can be used:
$ inigo a.dv b.mpg c.png
Properties can be assigned to each file:
$ inigo a.dv in=50 out=100 b.mpg out=500 c.png out=500
MLT will take care of 'normalising' the output of a producer to ensure
that the consumer gets what it needs. So, in the case above, the mlt
framework will ensure that images are rescaled and audio resampled to meet
the requirements of your configuration (which, by default, will be PAL).
See 'Appendix A: Normalisation Rules' below.
Filters:
Filters are frame modifiers - they can change the contents of the audio or
the images associated to a frame.
$ inigo a.dv -filter greyscale
As with producers, properties may be specified on filters too.
Again, in and out properties are common to all, so to apply a filter to a
range of frames, you would use something like:
$ inigo a.dv -filter greyscale in=0 out=50
Again, filters have their own set of rules about properties and will
silently ignore properties that do not apply.
Groups:
The -group switch is provided to force default properties on the following
'services'. For example:
$ inigo -group in=0 out=49 clip*
would play the first 50 frames of all clips that match the wild card
pattern.
Note that the last -group settings also apply to the following filters,
transitions and consumers, so:
$ inigo -group in=0 out=49 clip* -filter greyscale
is *probably not* what you want (ie: the greyscale filter would only be
applied to the first 50 frames).
To shed the group properties, you can use any empty group:
$ inigo -group in=0 out=49 clip* -group -filter greyscale
Attached Filters:
As described above, the -filter switch applies filters to an entire track. To
localise filters to a specific clip on a track, you have to know information
about the lengths of the clip and all clips leading up to it. In practise,
this is horrifically impractical, especially at a command line level (and not
even that practical from a programing point of view...).
The -attach family of switches simplify things enormously. By default, -attach
will attach a filter to the last service created, so:
$ inigo clip1.dv clip2.dv -attach greyscale clip3.dv
would only apply the filter to clip2.dv. You can further narrow down the area of
the effect by specifying in/out points on the attached filter.
This might seem simple so far, but there is a catch... consider the following:
$ ingo clip1.dv -attach watermark:+hello.txt -attach invert
The second attached filter is actually attached to the watermark. You might
think, yay, nice (and it is :-)), but, it might not be what you want. For example
you might want to attach both to clip1.dv. To do that, you can use:
$ ingo clip1.dv -attach-cut watermark:+hello.txt -attach-cut invert
As you shall see below, there are still another couple of gotchas associated to
-attach, and even another variant :-).
Mixes:
The -mix switch provides the simplest means to introduce transitions between
adjacent clips.
For example:
$ inigo clip1.dv clip2.dv -mix 25 -mixer luma -mixer mix:-1
would provide both an audio and video transition between clip1 and clip2.
This functionality supercedes the enforced use of the -track and -transition
switches from earlier versions of inigo and makes life a lot easier :-).
These can be used in combination, so you can for example do a fade from black
and to black using the following:
$ inigo colour:black out=24 clip1.dv -mix 25 -mixer luma \
colour:black out=24 -mix 25 -mixer luma
while this may not be immediately obvious, consider what's happening as the
command line is being parsed from left to right:
Input: Track
----------------------- -----------------------------------------------------
colour:black out=24 [black]
clip1.dv [black][clip1.dv]
-mix 25 [black+clip1.dv][clip1.dv]
-mixer luma [luma:black+clip1.dv][clip1.dv]
colour:black out=24 [luma:black+clip1.dv][clip1.dv][black]
-mix 25 [luma:black+clip1.dv][clip1.dv][clip1.dv+black]
-mixer luma [luma:black+clip1.dv][clip1.dv][luma:clip1.dv+black]
Obviously, the clip1.dv instances refer to different parts of the clip, but
hopefully that will demonstrate what happens as we construct the track.
You will find more details on the mix in the framework.txt.
Mix and Attach:
As noted, -attach normally applies to the last created service - so, you can
attach a filter to the transition region using:
$ inigo clip1.dv clip2.dv -mix 25 -mixer luma -attach watermark:+Transition.txt
Again, nice, but take care - if you want the attached filter to be associated
to the region following the transition, use -attach-cut instead.
Splits, Joins, Removes and Swaps:
COMPLEX - needs simplification....
Introducing Tracks and Blanks:
So far, all of the examples have shown the definition of a single
playlist, or more accurately, track.
When multiple tracks exist, the consumer will receive a frame
from the 'highest numbered' track that is generating a non-blank
frame.
It is best to visualise a track arrangement, so we'll start with
an example:
$ inigo a.dv -track b.dv in=0 out=49
This can be visualised as follows:
+------------------+
|a |
+-------+----------+
|b |
+-------+
Playout will show the first 50 frames of b and the 51st frame shown will be
the 51st frame of a.
This rule also applies to audio only producers on the second track, for
example, the following would show the video from the a track, but the audio
would come from the second track:
$ inigo a.dv -track b.mp3 in=0 out=49
To have the 51st frame be the first frame of b, we can use the -blank switch:
$ inigo a.dv out=49 -track -blank 49 b.dv
Which we can visualise as:
+-------+
|a |
+-------+-------------------+
|b |
+-------------------+
Now playout will continue as though a and b clips are on the
same track (which on its own, is about as useful as reversing the
process of slicing bread).
Transitions:
Where tracks become useful is in the placing of transitions.
Here we need tracks to overlap, so a useful multitrack
definition could be given as:
$ inigo a.dv out=49 \
-track \
-blank 24 b.dv \
-transition luma in=25 out=49 a_track=0 b_track=1
Now we're cooking - our visualisation would be something like:
+-------+
|a |
+---+---+--------------+
|b |
+------------------+
Playout will now show the first 25 frames of a and then a fade
transition for 25 frames between a and b, and will finally
playout the remainder of b.
Reversing a Transition:
When we visualise a track definition, we also see situations
like:
+-------+ +----------+
|a1 | |a2 |
+---+---+--------------+----+-----+
|b |
+-----------------------+
In this case, we have two transitions, a1 to b and b to a2.
In this scenario, we define a command line as follows:
$ inigo a.dv out=49 -blank 49 a2.dv \
-track \
-blank 24 b.dv out=99 \
-transition luma in=25 out=49 a_track=0 b_track=1 \
-transition luma in=100 out=124 reverse=1 a_track=0 b_track=1
Serialisation:
Inigo has a built in serialisation mechanism - you can build up
your command, test it via any consumer and then add a -serialise
file.inigo switch to save it.
The saved file can be subsequently used as a clip by either
miracle or inigo. Take care though - paths to files are saved as
provided on the command line....
A more expressive serialisation can be obtained with the westley consumer
- this will provide an xml document which can be used freely in inigo and
miracle.
See westley.txt for more information.
Missing Features:
Some filters/transitions should be applied on the output frame regardless
of which track it comes from - for example, you might have a 3rd text
track or a watermark which you want composited on every frame, and of
course, there's the obscure filter....
inigo only supports this in two invocations - as a simple example:
$ inigo a.dv -track -blank 100 b.dv -consumer westley:basic.westley
$ inigo basic.westley -filter watermark:watermark.png

@ -0,0 +1,187 @@
Installation Documentation
Copyright (C) 2004 Ushodaya Enterprises Limited
Author: Charles Yates <charles.yates@pandora.be>
Last Revision: 2004-04-13
INSTALL
-------
This document provides a description of the MLT project installation and
organisation.
Directories
-----------
The directory heirarchy is defined as follows:
+ demo - A selection of samples to show off capabilities.
+ docs - Location of all documentation
+ src - All project source is provided here
+ framework - The mlt media framework
+ modules - All services are defined here
+ avformat - libavformat dependent services
+ bluefish - Bluefish dependent services (*)
+ core - Independent MLT services
+ dv - libdv dependent services
+ fezzik - A giant (meta) service to load and normalise media
+ gtk2 - pango and pixbuf dependent services
+ mainconcept - mainconcept dependent services (*)
+ normalize - audio normalisation functions (**)
+ plus - throwaway silliness
+ resample - libresample dependent services (**)
+ sdl - SDL dependent services
+ vorbis - vorbis dependenent services
+ westley - Nice and clever XML services
+ xine - Xine-derived sources (**)
+ albino - A simple console (protocol level) example (**)
+ inigo - A media playing test application (**)
+ humperdink - A terminal-based example client
+ miracle - The server implementation (**)
+ tests - Reserved for regression and unit tests
+ valerie - Client API to access the server (**)
Additional subdirectories may be nested below those shown and should be
documented in their parent.
(*) Not posted to CVS due to licensing issues.
(**) Contains GPL dependencies or code.
Dependencies
------------
The MLT core is dependent on:
* a C99 compliant C compiler
* posix threading
* standard posix libraries
The MLT applications and libraries provided are all dependent on the core.
The modules have the following dependencies:
----------- ----------------------------------------------------------
MODULE DESCRIPTION
----------- ----------------------------------------------------------
avformat Provided from ffmpeg CVS and compiled as a shared library.
URL: http://ffmpeg.sf.net
----------- ----------------------------------------------------------
bluefish Bluefish hardware and software development kit
URL: http://www.bluefish444.com
----------- ----------------------------------------------------------
dv libdv 0.102 or later.
URL: http://libdv.sf.net
----------- ----------------------------------------------------------
gtk2 GTK2 and associated dependencies.
URL: http://www.gtk.org
----------- ----------------------------------------------------------
mainconcept Mainconcept MPEG and DVCPRO Release SDKs.
URL: http://www.mainconcept.com
----------- ----------------------------------------------------------
resample libsamplerate 0.15 or later
URL: http://www.mega-nerd.com/SRC/ (GPL)
----------- ----------------------------------------------------------
sdl SDL 1.2 or later.
URL: http://www.libsdl.org
----------- ----------------------------------------------------------
vorbis libvorbis 1.0.1 or later.
URL: http://www.vorbis.com/
----------- ----------------------------------------------------------
westley libxml2 2.5 or later.
URL: http://www.xmlsoft.org/
----------- ----------------------------------------------------------
Configuration
-------------
Configuration is triggered from the top level directory via a
./configure script.
Each source bearing subdirectory shown above have their own configure
script which are called automatically from the top level.
Typically, new modules can be introduced without modification to the
configure script and arguments are accepted and passed through to all
subdirectories.
More information on usage is found by running:
./configure --help
NB: This script must be run to register new services after a CVS checkout
or subsequent update.
Compilation
-----------
Makefiles are generated during configuration and these are based on
a per directory template which must be provided by the developer.
Testing
-------
To execute the mlt tools without installation, or to test a new version
on a system with an already installed mlt version, you should run:
. setenv
NB: This applies to your current shell only and it assumes sh or bash.
Installation
------------
The install is triggered by running make install from the top level
directory.
The framework produces a single shared object which is installed in
$prefix/lib/ and public header files which are installed in
$prefix/include/mlt/framework.
Valerie produces a single shared object which is installed in
$prefix/lib/ and public header which are installed in
$prefix/include/mlt/valerie.
Miracle produces a single exectuable which is installed in
$prefix/bin/, a library in $prefix/lib and associated header files in
$prefix/include.
The modules produce a shared object per module and update text files
containing a list of modules provided by this build. These are installed
in $prefix/share/mlt/modules. It is at the discretion of the module to
install additional support files.
To allow the development of external components, mlt-config and scripts
are generated and installed in $prefix/bin.
After install, only those modules listed are usable by the server. No
module is loaded unless explicitly requested via server configuration
or usage.
External modules are also placed in this $prefix/share/mlt/modules, and the
installation of those must modify the text file accordingly before they
will be considered at runtime.
Development
-----------
All compilation in the project has {top-level-dir}/src on the include path.
All headers are included as:
#include <framework/file.h>
All external modules have {prefix}/include/mlt on the include path. All
headers should also be included as:
#include <framework/file.h>
This allows migration of source between external and internal modules.
The configuration and Makefile template requirements will require
attention though.

@ -0,0 +1,52 @@
Open Source Development Policies and Procedures for MLT
by Dan Dennedy
Policies
--------
Any contribution to the "core" module must assign copyright to Ushodaya
Enterprises Limited because they need license control over that module.
The framework and valerie client libraries are covered under LGPL. Miracle,
inigo, albino, and humperdink applications are covered under GPL. Modules
should strive to be LGPL to make them available through the framework as LGPL.
Comments in the framework and valerie header files must be C-style, not C++.
Coding Style:
There are not a lot of rules, but we prefer brackets on their own line,
indents using tabs, liberal usage of spaces in statements and expressions, and
no hard line length. The code in src/framework serves as a good example.
Commit messages must be prefaced with the name of the changed files. This makes
the Subversion log more useful as a ChangeLog. For example,
docs/policies.txt: added policy about commit message
Increment the version number in ./configure on the first commit after a release
as well as just prior to a new release. This way we can track if someone is
using an unreleased version from the source code repository.
Procedures
----------
Update services.txt when you add or update a service.
Setting Copyright on Appropriated Code:
You do not want to be accused of copying someone's code and changing copyright
or license without permission. The license is straightforward: you must retain
the original author's license unless you receive explicit permission. There are
a few ways to approach the copyright declaration depending upon the
intermingling and changes. If you heavily comingle original and new code or
lightly modifiy the original code, you can retain the original's copyright
including the years, and then add your copyright for the current year. If you
can separate the MLT integration from the core subroutines, then you can put
the core subroutines into a separate file with the original copyright and just
copyright the MLT integration code as your own. However, if you have heavily
modified the original code beyond nearly all recognition, you can copyright it
as your own and attribute the original author as inspiration.
Bug Reporting:
First preference is to use the SourceForge tracker:
http://sourceforge.net/tracker/?group_id=96039&atid=613414
Second preference is in the mailing list:
mlt-devel@lists.sourceforge.net

File diff suppressed because it is too large Load Diff

@ -0,0 +1,35 @@
On 1/10/2004, Dan Dennedy ran the testing.txt against mlt albino and miracle.
NOTE: Discrepancies cited here may have impact on related functionality.
General
------------------------------------------------------------------------------
Server side error checks and related response error codes are not stringently enforced.
Not Implemented
------------------------------------------------------------------------------
NLS
USET points=ignore
USET eof=terminate
Incorrect Behaviour
------------------------------------------------------------------------------
Different Intentional Behaviour
------------------------------------------------------------------------------
Different forced Behaviour
------------------------------------------------------------------------------
killall miracle does not work when the SDL consumer is in use. requires killall -HUP
MLT Bugs
------------------------------------------------------------------------------
Please check the services.txt doc for known bugs related to MLT components.

@ -0,0 +1,599 @@
Miracle Test Procedure
Copyright (C) 2003 Ushodaya Enterprised Limited
Author: Dan Dennedy <dan@dennedy.org>
Last Revision: 2004-03-20
NOTE: THIS DOCUMENT REQUIRES REVISION TO NEW, EXPECTED BEHAVIOR FROM MIRACLE.
Tests are divided into 9 sections:
1. Command Line Usage
2. Unit Management
3. Server Configuration
4. Simple Playback
5. Multi-unit Playback
6. Unit Configuration
7. Advanced Playback
8. Bus Reset
9. Server Side Queuing
Each section contains many tests which I've divided into a minimum of two lines:
n.m action to carry out
--> expected result
Further lines may appear to show the actual results when they deviate from what
I expected or if there are special cases to consider.
Sequential tests are indicated as:
n.m.o action to carry out
--> expected result
It is suggested that you run top during the testing and note cpu hikes
or any excessive memory usage related to an operation.
0. Introduction
---------------
The tests following are by no means exhaustive, but they should cover typical
use cases - creativity is encouraged with more cases being added where necessary.
This document should also be maintained to dictate actual state, especially with
regard to a final release. Unit test cases are encouraged, but are excluded from
this document.
It is important to carry out the full test cycle when preparing a final release.
In this situation, please resist the temptation to bug fix a given test case and
resume the tests from that point onward - it is better to repeat from the
beginning (but you can of course employ common sense in this situation).
Before starting the final tests, please delete/backup your current
/etc/dv139d.conf file. This (more or less) ensures that tests are carried out
for a virgin install.
1. Command Line Usage
---------------------
Run these from the top level project directory
1.1.0 Start miracle in interactive mode: src/miracle/miracle -test
--> miracle starts interactively and reports:
(5) Starting server on 5250.
(5) miracle version 0.0.1 listening on port 5250
1.1.1 Stop the server by pressing Ctrl-C
--> miracle returns the following and returns control to the console:
(5) miracle version 0.0.1 server terminated.
1.2.2 Start miracle as a daemon: src/miracle/miracle
--> control returns to the console
1.2.3 Verify miracle is running: ps ax
--> several miracle processes are running
1.2.4 Verify successful miracle startup using syslog: sudo tail /var/log/syslog
--> miracle: miracle version 0.0.1 listening on port 5250
1.2.5 Verify connectivity on port 5250: telnet localhost 5250
--> 100 VTR Ready
1.2.6 Test clean disconnect: BYE
--> Connection closed by foreign host.
1.2.7 Stop the daemon: killall miracle
--> no errors
1.2.8 Verify a clean server shutdown: sudo tail /var/log/syslog
--> miracle: shutdown complete.
1.3.0 Start miracle on a different port: src/miracle/miracle -port 5260
1.3.1 Verify successful miracle startup using syslog: sudo tail /var/log/syslog
--> miracle: miracle version 0.0.1 listening on port 5260
1.3.2 Verify connectivity on port 5260: telnet localhost 5260
--> 100 VTR Ready
1.3.3 Test clean disconnect: BYE
--> Connection closed by foreign host.
1.3.4 Stop the daemon: killall miracle
--> no errors
2. Unit Management
------------------
Start the miracle server and connect to it with telnet or a protocol-
level client (albino).
2.1 List the AV/C devices on the bus: NLS
--> 201 OK
--> one or more lines listing devices with GUID in second column
2.2 Add a device as a miracle unit: UADD {sdl, bluefish}
--> 201 OK
--> U0
2.3 List the units: ULS
--> 201 OK
--> U0 ?? {sdl, bluefish} 1
--> It is important that the last column is '1' to indicate it is online.
2.4 List the units: ULS
--> 201 OK
--> U0 ?? {sdl, bluefish} 1
2.5 Attempt unit commands for a unit that does not exist: LOAD U6 foo
--> 403 Unit not found
2.6 Attempt unit commands without specifying a unit: PLAY
--> 402 Argument missing
2.7 Attempt unit commands for a unit: PLAY U0
--> 200 OK
2.8.0 Load a clip into an unit: LOAD U0 test.dv
--> 200 OK
2.7.1 Verify the status of the unit: USTA U0
--> 202 OK
--> 0 online "test.dv" 0 1000 25.00 0 ...
--> only the first 3 columns are relevant in this test
3. Server Configuration
-----------------------
Start miracle if not already started from a previous test.
3.1 Get the hard-coded default root property value: GET root
--> 202 OK
--> /
3.2 List the files and subdirectories at the root: CLS /
--> 201 OK
--> "bin/"
--> ...
3.3 Change the server root to a place where clips are stored: e.g.,
SET root=/tmp
--> 200 OK
3.4 Get the new value of the root property value: GET root
--> 202 OK
--> /tmp/
--> Notice that if you did not use a trailing slash in step 2.3, one is
added for you and appears in this step. This is normal and correct.
3.5 List the files and subdirectories at the root: CLS /
--> 201 OK
--> zero or more lines listing subdirectories followed by files.
3.6 Try to set a property that does not exist: SET foo=bar
--> 405 Argument value out of range
3.7 Try to set no property or value: SET
--> 402 Argument missing
3.8 Attempt a bogus command: FOO
--> 400 Unknown command
XXX 3.9 Attempt the incorrect case for a command: get root
XXX --> 400 Unknown command
3.10 Attempt case insensitivity of property key: GET Root
--> 202 OK
--> /tmp/
4. Simple Playback
-------------------
Start miracle or restart if already started.
Add an online unit.
Set the server root property if desired.
4.1.0 Load a clip into the unit: LOAD U0 test.dv
--> 200 OK
4.1.1 Check the unit status: USTA U0
--> 202 OK
--> 0 stopped "test.dv" 0 1000 25.00 0 ...
--> Only the first 3 columns are relevant in this test.
--> The remaining columns are only relevant to the tester.
4.2.0 Play the clip: PLAY U0
--> 200 OK
--> Verify audio and video output
4.2.1 Check the unit status: USTA U0
--> 202 OK
--> 0 playing "test.dv" 1739 1000 25.00 0 ...
--> Only the first 3 columns are relevant in this test.
--> The remaining columns are only relevant to the tester.
4.3.0 Pause playback: PAUSE U0
--> 200 OK
--> Verify video continues, but audio is muted.
4.3.1 Check the unit status: USTA U0
--> 202 OK
--> 0 paused "test.dv" 1739 0 25.00 0 ...
--> The fifth column --------^ should be 0; it indicates speed.
4.3.2 Stop playback: STOP U0
--> 200 OK
--> The analog video output stops
4.3.3 Pause playback: PAUSE U0
--> 200 OK
--> Analog video starts again, but it is held on the same frame
paused in 4.3.0.
4.3.4 Stop playback: STOP U0
--> 200 OK
--> The analog video signal ceases.
4.3.5 Rewind the unit: REW U0
--> 200 OK
4.3.6 Play the unit: PLAY U0
--> 200 OK
--> Analog audio and video are produced from the beginning of the file.
4.4 Stop the server during playback and ensure clean shutdown.
5. Multi-unit Playback
-----------------------
Start miracle or restart if already started.
Add *2* online units.
Set the server root property if desired.
5.1.0 Load a clip into one unit: LOAD U0 test.dv
--> 200 OK
5.1.1 Load a clip into the other unit: LOAD U1 test.dv
--> 200 OK
5.1.2 Start playing one unit: PLAY U0
--> 200 OK
--> Verify audio and video output
5.1.3 Start playing the other unit: PLAY U1
--> 200 OK
--> Verify audio and video output of both units
5.2 Verify independence of units by pausing one of them: PAUSE U0
--> 200 OK
--> Verify video continues, but audio is muted on the first unit only.
5.3 Stop the server during multi-unit playback and ensure clean shutdown.
6. Advanced Playback
--------------------
Start miracle or restart if already started.
Add *2* online units.
Set the server root property if desired.
Trick play modes:
6.1.0 Load a clip: LOAD U0 test.dv
--> 200 OK
6.1.1 Start playback by pausing on the first frame: PAUSE U0
--> 200 OK
--> analog video starts, but audio is muted.
6.1.2 Play fast forward: FF U0
--> 200 OK
--> verify video is playing fast in the forward direction.
6.1.3 Get unit status: USTA U0
--> 202 OK
--> 0 playing "test.dv" 219 2000 25.00 0 ...
--> The important column is --^, indicates speed
6.1.4 Play fast reverse: REW U0
--> 200 OK
--> verify analog video output is fast in the reverse direction.
6.1.5 Get unit status: USTA U0
--> 202 OK
--> 0 playing "test.dv" 4621 -2000 25.00 0 ...
--> The important column is ---^, negative mean reverse
6.1.6 Play slow forward: PLAY U0 500
--> 200 OK
--> Verify the analog video output is slow in the forward direction.
6.1.7 Play reverse normal speed: PLAY U0 -1000
--> 200 OK
--> Verify the analog video output is at a normal speed in the reverse direction.
--> Audio output is reverse, but not the field order of video
Loading while playing:
6.2.0 Stop the unit (might be playing): STOP U0
--> 200 OK
6.2.1 Rewing the unit: REW U0
--> 200 OK
6.2.2 Start playing: PLAY U0
--> 200 OK
--> verify analog audio and video output
6.2.3 Load another clip: LOAD test002.dv
--> 200 OK
--> playback seamlessly switches to the new clip
--> verify the analog appearance of the video makes a clean switch
6.2.4 Load another clip, this time with in and out points:
LOAD test.dv 100 500 (whatever works for your test footage)
--> 200 OK
--> verify the analog appearance of the video makes a clean switch
6.2.5 Get unit status: USTA U0
--> 202 OK
--> 0 playing "test.dv" 403 1000 25.00 100 ...
--> verify position -----^ is beyond --^ in point, last column is the out
point specified in the previous step.
Edit points:
6.3.0 Load a clip: LOAD U0 test.dv
--> 200 OK
6.3.1 Pause the playback unit: PAUSE U0
--> 200 OK
6.3.2 Set the in point: SIN U0 100
--> 200 OK
--> verify the frame displayed in analog video out changes
6.3.4 Get the unit status: USTA U0
--> 202 OK
--> 0 paused "test.dv" 100 0 25.00 100 ...
--> verify position ---^ and in ---^
6.3.5 Change the mode of the unit to not restrict playback to the edit
region: USET U0 points=ignore
--> 200 OK
6.3.6 Jump to a frame before the in frame: GOTO U0 50
--> 200 OK
6.3.7 Get the unit status: USTA U0
--> 202 OK
--> 0 paused "test.dv" 50 0 25.00 100 ...
--> position ----------^ preceeds -^ (in)
6.3.8 Set the unit mode to restrict playback to the edit region: USET U0 points=use
--> 200 OK
--> verify frame on analog video output changes
6.3.9 Get the unit status: USTA U0
--> 202 OK
--> 0 paused "test.dv" 100 0 25.00 100 ...
--> verify position ---^ and in ---^
6.3.10 Clear the in point: SIN U0 -1
--> 200 OK
6.3.11 Get the unit status: USTA U0
--> 202 OK
--> 0 paused "test.dv" 100 0 25.00 0 ...
--> verify the in point is reset --^
The above sequence should be repeated in a similar manner for the out point
using the SOUT command.
Transfer:
6.4.0 Load a clip into the first unit: LOAD U0 test.dv
--> 200 OK
6.4.1 Load a clip into the second unit: LOAD U1 test002.dv
--> 200 OK
6.4.2 Start playing the first unit: PLAY U0
--> 200 OK
--> verify audio and video analog output
6.4.3 Set an in point on the clip in the second unit: SIN U1 100
--> 200 OK
6.4.4 Play the second unit: PLAY U1
--> 200 OK
--> note the beginning footage
6.4.5 Transfer the clip from the second to the first unit: XFER U1 U0
--> 200 OK
--> verify a clean switch on the analog audio and video output of the first unit.
--> upon transfer it should play the same footage previewed in step 6.4.4
6.4.5 Get the first unit's status: USTA U0
--> 202 OK
--> 0 playing "test002.dv" 963 1000 29.97 100 2502
--> note the in point set from U1 ---------^
7. Unit Configuration
---------------------
Start miracle or restart if already started.
Add an online unit.
Set the server root property if desired.
7.1.0 Load a short clip: LOAD U0 test.dv
--> 200 OK
7.1.1 Play a clip: PLAY U0
--> 200 OK
--> Wait until it gets to the end, and it should pause on the last frame.
7.1.2 Make the clip start looping: USET U0 eof=loop
--> 200 OK
--> verify the clip starts playing from the beginning and loops
7.2.0 Set the in point: SIN U0 10
--> 200 OK
--> playback pauses at in point (verify with USTA U0)
7.2.1 Set the out point: SOUT U0 200
--> 200 OK
--> playback pauses at in point (verify with USTA U0)
7.2.2 Start playing again: PLAY U0
--> 200 OK
--> verify playback loops between in and out points
7.3 Tell the unit to ignore the edit points: USET U0 points=ignore
--> 200 OK
--> verify playback loops over entire video file
7.4 Get the current value of the points property: UGET U0 points
--> 202 OK
--> ignore
9. Server Side Queuing
----------------------
Only one unit is used for these test cases, and
users are encouraged to test with multiple units online. It is assumed that a
number of dv files are available for use in the servers ROOT directory - this
document assumes that they are named test001.dv and up.
9.1.0 Start miracle in interactive mode and add a unit (all tests will assume U0)
--> server started with unit 0 available
9.1.1 Obtain a miracle shell (via telnet or albino).
--> 100 VTR (if reported by the client)
9.1.2 Load a clip with LOAD U0 test001.dv and PAUSE U0
--> 200 OK
9.1.3 List the clips with LIST U0
--> 201 OK
--> 1
--> 0 "test001.dv" 0 6999 7000 7000 25.00
--> The 1 on the second line denotes the number of times the list has been changed
via user commands (known as the 'generation' number).
--> The third line and beyond reports the clip index (from 0 to n), file loaded, in point,
out point, real size of the file and the calculated size (out - in + 1 ).
9.1.4 Check the unit status with USTA U0
--> 202 OK
--> 0 paused "test001.dv" 0 0 25.00 0 6999 7000 "test001.dv" 0 0 6999 7000 1 1 0
--> The last two fields indicate the generation number and current clip resp.
9.1.5 Append a clip with APND U0 test002.dv followed by LIST U0
--> 201 OK
--> 2
--> 0 "test001.dv" 0 6999 7000 7000
--> 1 "test002.dv" 0 6999 7000 7000
--> Check that USTA U0 reports a generation of 2 and current clip of 0
9.1.6 Move clip 1 to clip 0 with MOVE U0 1 0 followed by LIST U0
--> 201 OK
--> 3
--> 0 "test002.dv" 0 6999 7000 7000
--> 1 "test001.dv" 0 6999 7000 7000
--> Check that USTA U0 reports a generation of 3 and current clip of 1
9.1.7 Move clip 0 to clip 1 with MOVE U0 0 1 followed by LIST U0
--> 201 OK
--> 4
--> 0 "test001.dv" 0 6999 7000 7000
--> 1 "test002.dv" 0 6999 7000 7000
--> Check that USTA U0 reports a generation of 4 and current clip of 0
--> Note that the order in which you run 9.1.6 and 9.1.7 shouldn't matter as the
result will be identical
9.1.8 Change the position to the next clip with GOTO U0 0 +1
--> 200 OK
--> Check that USTA U0 reports a generation of 4 and current clip of 1
9.1.9 Remove all but the playing clip with CLEAN U0 followed by LIST U0
--> 201 OK
--> 5
--> 0 "test002.dv" 0 6999 7000 7000
--> Check that USTA U0 reports a generation of 5 and current clip of 0
9.1.10 Insert test001.dv back into the list using INSERT U0 test001.dv and run LIST U0
--> 201 OK
--> 6
--> 0 "test001.dv" 0 6999 7000 7000
--> 1 "test002.dv" 0 6999 7000 7000
--> Check that USTA U0 reports a generation of 6 and current clip of 1
9.1.11 Insert test003.dv at position 2 using INSERT U0 test001.dv 3 and run LIST U0
--> 201 OK
--> 7
--> 0 "test001.dv" 0 6999 7000 7000
--> 1 "test002.dv" 0 6999 7000 7000
--> 2 "test003.dv" 0 6999 7000 7000
--> Check that USTA U0 reports a generation of 7 and current clip of 1
9.1.12 Change the in point of the current clip using SIN U0 5000 and run LIST U0
--> 201 OK
--> 8
--> 0 "test001.dv" 0 6999 7000 7000
--> 1 "test002.dv" 5000 6999 7000 2000
--> 2 "test003.dv" 0 6999 7000 7000
--> Check that USTA U0 reports a generation of 8 and current clip of 1
9.1.13 Change the out point of the following clip using SOUT U0 5000 +1 and run LIST U0
--> 201 OK
--> 9
--> 0 "test001.dv" 0 6999 7000 7000
--> 1 "test002.dv" 5000 6999 7000 2000
--> 2 "test003.dv" 0 5000 7000 5001
--> Check that USTA U0 reports a generation of 9 and current clip of 2
9.1.14 Change the in point of the current clip to 1000 using SIN U0 1000 and run LIST U0
--> 201 OK
--> 10
--> 0 "test001.dv" 0 6999 7000 7000
--> 1 "test002.dv" 5000 6999 7000 2000
--> 2 "test003.dv" 1000 5000 7000 4001
--> Check that USTA U0 reports a generation of 10 and current clip of 2
9.1.15 Ignore the in/out points by running USET U0 points=ignore and run LIST U0
--> 201 OK
--> 11
--> 0 "test001.dv" 0 6999 7000 7000
--> 1 "test002.dv" 5000 6999 7000 7000
--> 2 "test003.dv" 1000 5000 7000 7000
--> Check that USTA U0 reports a generation of 11 and current clip of 2
9.1.16 Turn the in/out points on again by running USET U0 points=use and run LIST U0
--> 201 OK
--> 12
--> 0 "test001.dv" 0 6999 7000 7000
--> 1 "test002.dv" 5000 6999 7000 2000
--> 2 "test003.dv" 1000 5000 7000 4001
--> Check that USTA U0 reports a generation of 12 and current clip of 2
9.1.17 Remove the current clip using REMOVE U0 and run LIST U0
--> 201 OK
--> 13
--> 0 "test001.dv" 0 6999 7000 7000
--> 1 "test002.dv" 5000 6999 7000 2000
--> Check that USTA U0 reports a generation of 13 and current clip of 0
9.1.17 Remove the next clip using REMOVE U0 +1 and run LIST U0
--> 201 OK
--> 14
--> 0 "test001.dv" 0 6999 7000 7000
--> Check that USTA U0 reports a generation of 14 and current clip of 0

@ -0,0 +1,861 @@
Valerie API Documentation
Copyright (C) 2004 Ushodaya Enterprised Limited
Author: Charles Yates <charles.yates@pandora.be>
Last Revision: 2004-03-20
TABLE OF CONTENTS
-----------------
0. Overview
0.1. Intended Audience
0.2. Terminology
1. Definition of a Parser
1.1. Construction of a Local Parser
1.2. Construction of a Remote Parser
1.3. Using the Parser
1.4. Closing the Parser
2. The High Level Parser Wrapper
2.1. Connecting
2.2. valerie_error_code
2.3. Using the High Level Wrapper
2.4. Obtaining Directory Contents
2.5. Obtaining the Node List
2.6. Obtaining the Unit List
2.7. Unit Status Information
2.8. Server Side Queuing APIs
2.9. Accessing the Low Level Parser Directly
2.10. Cleaning up
2.11. Examples
3. The Low Level Parser API
3.1. Executing a Command
3.2. Interpreting valerie_response
3.3. Accessing Unit Status
APPENDIX A - COMPILATION AND LINKING
APPENDIX B - COMPLETE HIGH LEVEL PARSER WRAPPER API LISTING
APPENDIX C - COMPLETE LOW LEVEL PARSER API LISTING
APPENDIX D - REFERENCES
0. Overview
-----------
This document details how applications interface to DVCP functionality.
0.1. Intended Audience
----------------------
This document draws heavily upon the DVCP design (1) and assumes a basic
knowledge of the functionality provided by the DVCP core.
It is aimed at developers who wish to use or maintain the API.
0.2. Terminology
----------------
The API is designed to allow client applications the ability to communicate
to a standalone miracle server or entirely embed the DVCP core in an
instance of a client application.
The distinction between the two is defined by the construction of the
'parser'.
This 'parser' can be used to issue DVCP commands and receive responses and
a 'high level parser wrapper' is provided to simplify the usage and
decouple the application from the DVCP command set.
1. Definition of a Parser
-------------------------
The parser provides a low level API which allows text DVCP commands to be
executed with responses being returned to the caller. Commands and
responses are ASCII formatted text.
Two parsers are provided - local and remote.
The local parser is the physical implementation which takes commands and
executes them.
The remote parser is a network abstraction that forwards commands to a
miracle instance that hosts a local parser.
1.1. Construction of a Local Parser
-----------------------------------
To construct a local parser you must have:
#include <miracle/miracle_local.h>
and code to initialise the parser is as follows:
valerie_parser parser = miracle_parser_init_local( );
See Appendix A for compilation and linking details.
1.2. Construction of a Remote Parser
------------------------------------
To construct a remote parser you must have:
#include <valerie/valerie_remote.h>
and code to initialise the parser is as follows:
valerie_parser parser = valerie_parser_init_remote( "server", port );
See Appendix A for compilation and linking details.
1.3. Using the Parser
---------------------
Although the parser can be used directly to send commands and receive
responses, this low level usage puts the onus on the developer to parse the
responses in a meaningful way.
Although this usage is not strictly forbidden by applications, it is
discouraged as construction of commands and meaningful parsing of responses
leads to the clients being unnecessarily dependent on the servers input and
output.
As a result, a higher level Parser Wrapper API is provided - this API
encapsulates the command construction and response parsing.
The following 2 sections provide details on these modes of access.
1.4. Closing the Parser
-----------------------
Regardless of use, it is the constructors responsibility to close the
parser before it goes out of scope. This is done via:
valerie_parser_close( parser );
2. The High Level Parser Wrapper
--------------------------------
The recommended way to access the parser, is via the valerie API. To use
this API, you must have:
#include <valerie/valerie.h>
and code to construct the wrapper is:
valerie dv = valerie_init( parser );
Note that either remote or local parsers can be used here and there is no
difference in usage, though some error returns will not be applicable to
both.
It is recommended that applications honour and deal with the error returns
of both as this allows applications to interchange parsers.
Also note that valerie is not threadsafe, so you should not use the same
structure in multiple threads. The correct solution to this is to create a
valerie per thread - you may safely use the same parser for each thread ie:
/* valerie for the application */
valerie dv = valerie_init( parser );
/* valerie for the status handling thread. */
valerie dv_status = valerie_init( parser );
For the purposes of simplification, the remainder of this section assumes
that a remote parser is in use.
2.1. Connecting
---------------
Once constructed, the next thing to do is 'connect':
valerie_error_code error = valerie_connect( dv );
This function call initialises the parser (ie: if it's remote, it
establishes a connection to the server, or if it's local, it initialises
the state of the units and supporting objects).
Note that if you have multiple valerie instances on the same parser you
should only connect one of the instances.
2.2. valerie_error_code
----------------------
All but a couple of the functions that make up the valerie API return a
valerie_error_code.
These are defined as follows:
valerie_ok = 0,
valerie_malloc_failed,
valerie_unknown_error,
valerie_no_response,
valerie_invalid_command,
valerie_server_timeout,
valerie_missing_argument,
valerie_server_unavailable,
valerie_unit_creation_failed,
valerie_unit_unavailable,
valerie_invalid_file,
valerie_invalid_position
In most cases, it is sufficient to check on a return of valerie_ok.
To obtain a textual description of a particular error, you can use:
char *valerie_error_description( valerie_error_code );
2.3. Using the High Level Wrapper
---------------------------------
The following code snippet assumes that dv is an initialised and connected
valerie structure:
valerie_error_code error = valerie_unit_play( dv, 0 );
if ( error == valerie_ok )
fprintf( stderr, "Unit 0 is now playing\n" );
else
fprintf( stderr, "Play on unit 0 failed: %s\n",
valerie_error_description( error ) );
The complete interface to valerie is listed in Appendix B of this document.
2.4. Obtaining Directory Contents
--------------------------------
To obtain a list of files and subdirectories in a given directory relative
to the ROOT property of the server, DVCP provides the CLS command.
A valid execution of CLS would be something like:
CLS "/Stuff"
would provide a response formatted as follows:
201 OK
"More Stuff/"
"file0001.dv" 15552000
"file0002.dv" 15552000
with a trailing empty line.
The first line indicates the error value, the second line shows an example
of a subdirectory and the 3rd and 4th line lists two files that happen to
exist in the directory.
valerie provides a high level view on this which automatically parses the
response from the server correctly via the valerie_dir structures and
related functions.
An example of use is as follows:
valerie_dir dir = valerie_dir_init( dv, "/Stuff" );
valerie_error_code error = valerie_dir_get_error_code( dir );
if ( error == valerie_ok )
{
if ( valerie_dir_count( dir ) > 0 )
{
valerie_dir_entry_t entry;
int index = 0;
for ( index = 0; index < valerie_dir_count( dir ); index ++ )
{
valerie_dir_get( dir, index, &entry );
if ( entry.dir )
printf( "<%s>\n", entry.name );
else
printf( "%30s %8d", entry.name, entry.size );
}
}
else
{
fprintf( stderr, "Directory is empty\n" );
}
}
else
{
fprintf( stderr, "Directory listing failed: %s\n",
valerie_error_description( error ) );
}
valerie_dir_close( dir );
Note that entry.name provides the name of the file or directory without the
directory prefix. As a convenience, entry.full provides the prefixed name,
so you could subsequently use:
error = valerie_unit_load( dv, 0, entry.full );
to load unit 0 with an entry.
2.5. Obtaining the Node List
----------------------------
Currently not defined by miracle.
2.6. Obtaining the Unit List
----------------------------
To obtain a list of defined units, DVCP provides the ULS command.
A valid execution of ULS would be:
ULS
and would provide a response formatted as follows:
201 OK
U0 00 sdl:360x288 1
with a trailing empty line.
The fields of each record in the response dictate unit, node, mlt consumer and
online status respectively.
valerie provides a high level view on this which automatically parses the
response from the server correctly via the valerie_units structures and
related functions.
An example of use is as follows:
valerie_units units = valerie_units_init( dv );
valerie_error_code error = valerie_units_get_error_code( units );
if ( error == valerie_ok )
{
if ( valerie_units_count( units ) > 0 )
{
valerie_unit_entry_t entry;
int index = 0;
for ( index = 0; index < valerie_units_count( units ); index ++ )
{
valerie_units_get( units, index, &entry );
printf( "U%d %02d %s %s\n",
entry.unit,
entry.node,
entry.guid,
entry.online ? "online" : "offline" );
}
}
else
{
fprintf( stderr, "Unit list is empty\n" );
}
}
else
{
fprintf( stderr, "Unit listing failed: %s\n",
valerie_error_description( error ) );
}
valerie_units_close( units );
2.7. Unit Status Information
----------------------------
There are two methods for a client to obtain unit status information.
The first is via the DVCP USTA command, which would normally be accessed
via:
USTA U0
and would provide a response formated as follows:
202 OK
0 playing "a.dv" 58 1000 25.00 0 6999 7000 "a.dv" 157 0 6999 7000 1 4 0
with no trailing empty line.
The entries in the record are:
* Unit
* State (undefined, offline, not_loaded, stopped, playing,
paused, disconnected [when server dies])
* Name of Clip
* Position in clip
* Speed * 1000
* Frames per second
* Start of clip (in point)
* End of clip (out point)
* Length of clip
* Read ahead clip
* Read ahead position
* Read ahead clip in
* Read ahead clip out
* Read ahead clip length
* Seekable flag
* Playlist generation
* Clip index
Again, valerie provides a high level means for obtaining this via the
valerie_unit_status function and valerie_status structures:
valerie_status_t status;
valerie_error_code error = valerie_unit_status( dv, 0, &status );
if ( error == valerie_ok )
{
switch( status.status )
{
case unit_offline:
printf( "offline " );
break;
case unit_undefined:
printf( "undefined " );
break;
case unit_not_loaded:
printf( "unloaded " );
break;
case unit_stopped:
printf( "stopped " );
break;
case unit_playing:
printf( "playing " );
break;
default:
printf( "unknown " );
break;
}
printf( "%06lld %06lld %06lld %s\n", status.in,
status.position,
status.out,
status.clip );
}
else
{
fprintf( stderr, "Unit status failed: %s\n",
valerie_error_description( error ) );
}
The second approach for obtaining a units status is via automatic
notification.
This is done via the valerie_notifier API. To obtain the notifier from the
high level API, you can use:
valerie_notifier notifier = valerie_get_notifier( dv );
To obtain the last status associated to a unit, you can use:
int unit = 1;
valerie_status_t status;
valerie_notifier_get( notifier, &status, unit );
To wait for the next status from any unit, you can use:
valerie_notifier_wait( notifier, &status );
If you wish to trigger the action associated to your applications wait
handling of a particular unit, you can use:
valerie_notifier_get( notifier, &status, unit );
valerie_notifier_put( notifier, &status );
See Examples below for details on this.
The complete list of fields in the status structure are:
int unit;
unit_status status;
char clip[ 2048 ];
int64_t position;
int speed;
double fps;
int64_t in;
int64_t out;
int64_t length;
char tail_clip[ 2048 ];
int64_t tail_position;
int64_t tail_in;
int64_t tail_out;
int64_t tail_length;
int seekable;
int generation;
int clip_index;
You will always receive a status record for every frame output.
The read ahead information is provided for client side queuing. Client side
queuing assumes that uset eof=pause is applied to the unit. A client can
detect when the previously scheduled clip is played out by using the read
ahead information and schedule the next clip. While this mode of operation
is still supported, it is recommended that new clients use the server side
queuing mechanism which is described in the following section.
2.8. Server Side Queueing APIs
------------------------------
This section describes the APIs available to provide server side queueing.
The concept is that each unit maintains its own playlist, containing multiple
clips. Associated to the playlist is a generation number which is incremented
on each modification to the playlist. The current playlist generation is
provided in the status record in order for a client to know when to refresh
its presentation of the list. The status record also indicates which clip is
currently active.
Actions that can be carried out on the playlist are summarised as:
* list - list all the clips and associated in/out points and size
* loading a clip - a load will wipe the current list and replace it with the
specified clip
* appending a clip - append will always place the specified clip at the end
of the playlist
* inserting a clip - insert will place a new clip at the specified position
in the playlist
* moving a clip - move will allow clips can be moved in the playlist
* removing a clip - remove will remove the specified clip from the playlist
* clean - clean will remove all but the playing clip from the playlist
Additionally, the following existing actions are clip aware:
* goto allows you to move the current play position to a specific clip position
* set in/out points allows you to modify clip in and out points
Backward compatability has been maintained by the addition of a clip-aware
family of APIs which have the naming convention of valerie_unit_clip_*.
These are listed in Appendix B.
The following shows an example of obtaining the clips queued on unit 0:
valerie_list list = valerie_list_init( dv, 0 );
valerie_list_entry_t entry;
int index;
printf( "Generation = %d\n", list->generation );
for ( index = 0; index < valerie_list_count( list ); index ++ )
{
valerie_list_get( list, index, &entry );
printf( "%d %s %d %d %d %d\n",
entry.clip,
entry.full,
entry.in,
entry.out,
entry.max,
entry.size );
}
valerie_list_close( list );
To load a clip on unit 0:
valerie_unit_load( dv, 0, "/path/clip.dv" );
To append a clip on unit 0:
valerie_unit_append( dv, 0, "/path/clip.dv", -1, -1 );
Note that the last two arguments specify the in and out points of the clip
with -1 denoting dfaults of the entirety of the file.
To insert a clip at position 0 on unit 0, we can use the following:
valerie_unit_clip_insert( dv, 0, clip_absolute, 0, "/path/clip.dv", -1, -1 );
The 3rd and 4th arguments here are common to all the valerie_unit_clip functions.
They take the form of either [clip_absolute, n] to indicate an absolute clip
index, or [clip_relative, n] to indicate a clip index relative to the
currently playing clip.
So, to insert a clip immediately before the currently playing clip, we can
use:
valerie_unit_clip_insert( dv, 0, clip_relative, -1, "/path/clip.dv", -1, -1 );
To move the current clip to the next position in the list:
valerie_unit_clip_move( dv, 0, clip_relative, 0, clip_relative, 1 );
To remove a specific clip:
valerie_unit_clip_remove( dv, 0, clip_absolute, index );
To remove all but the currently playing clip:
valerie_unit_clean( dv, 0 );
To goto the first frame in the first clip, you can use:
valerie_unit_clip_goto( dv, 0, clip_absolute, 0, 0 );
To set the in and out points on the current clip:
valerie_unit_clip_set_in( dv, 0, clip_relative, 0, 0 );
valerie_unit_clip_set_out( dv, 0, clip_relative, 0, 1000 );
A more complete example of use of the server side can queuing can be found
at:
http://users.pandora.be/acp/rugen
The demo client provided with valerie is used for retaining backward
compatability with the client side queuing API.
2.9. Accessing the Low Level Parser Directly
--------------------------------------------
The low level parser and its associated structures can be accessed directly
from the high level API, but is very occasionally actually needed.
The methods are provided via a pair of high level methods:
valerie_error_code error = valerie_execute( dv, 1024, "USTA U%d", unit );
valerie_response response = valerie_get_last_response( dv );
int index = 0;
for ( index = 0; index < valerie_response_count( response ); index ++ )
printf( "%d: %s\n", index, valerie_response_get_line( response,index ) );
More details on the valerie_response structure can be found in section 3 of this
document.
2.10. Cleaning up
-----------------
Before the valerie and parser go out of scope, you need to run:
valerie_close( dv );
valerie_parser_close( parser );
Note that you should close all valerie instances before closing the parser.
2.11. Examples
--------------
Please refer to albino and humperdink source for examples provided with
the project. Additional examples can be found via google with gdv1394 and
poldo.
3. The Low Level Parser API
---------------------------
The low level parser API provides a very simple mechanism for constructing
commands and receiving responses.
As described in section 2, a parser is constructed as local or remote and
this is sufficient for constructing the low level parser.
3.1. Executing a Command
------------------------
All commands can be executed via the single variable argument function
valerie_parser_executef and this function returns a valerie_response, ie:
valerie_response response = valerie_parser_executef( parser, "CLS \"%s\"", dir );
Note that no carriage return/line feed is required (adding this is
erroneous).
It is the receiver of the response who is responsible for closing it.
valerie_response_close( response );
3.2. Interpreting valerie_response
-----------------------------
The response received can be NULL, but it is safe to call:
int error = valerie_response_get_error_code( response );
which will return:
* -1 if response is NULL,
* -2 if there is no content to the response,
* 0 if the responses first line does not correspond to a valid DVCP response
* or the DVCP protocol error code returned on the first line of the response
A simple use of a valerie_response structure is as follows:
valerie_response response = valerie_parser_executef( parser, "CLS \"%s\"", dir );
int error = valerie_response_get_error_code( response );
if ( error >= 0 )
{
int index = 0;
for ( index = 0; index < valerie_response_count( response ); index ++ )
printf( "%3d: %s\n", index, valerie_response_get_line( response, index ) );
}
else
{
/* interpret error */
}
valerie_response_close( response );
Note that it is safe to call valerie_response_close regardless of the error
condition indicated.
3.3. Accessing Unit Status
--------------------------
As with the high level parser, there are two alternatives to obtain unit
status information - either via the USTA DVCP command or via the
valerie1394_notifier.
The latter is the recommended way for any applications which wish to extract
meaningful information from the status while avoiding the requirement to
duplicate the parsing process in a specific client.
The notifier can be obtained by:
valerie_notifier notifier = valerie_parser_get_notifier( parser );
The use of the notifier with the low level parser is identical to that
dictated in Section 2 - to obtain the last status associated to a unit,
you can use:
int unit = 1;
valerie_status_t status;
valerie_notifier_get( notifier, &status, unit );
To wait for the next status from any unit, you can use:
valerie_notifier_wait( notifier, &status );
APPENDIX A - COMPILATION AND LINKING
------------------------------------
Compilation flags are:
-I <prefix>/include
where prefix defaults to /usr/local.
Linking flags for a client are:
-L <prefix>/lib/ -lvalerie
Or for a local parser:
-L <prefix>/lib/ -lmiracle
Note that you never need both libs.
APPENDIX B - COMPLETE HIGH LEVEL PARSER WRAPPER API LISTING
-----------------------------------------------------------
valerie valerie_init( valerie_parser );
valerie_error_code valerie_connect( valerie );
valerie_error_code valerie_set( valerie, char *, char * );
valerie_error_code valerie_get( valerie, char *, char *, int );
valerie_error_code valerie_unit_add( valerie, char * );
valerie_error_code valerie_unit_load( valerie, int, char * );
valerie_error_code valerie_unit_load_clipped( valerie,int,char *,long,long );
valerie_error_code valerie_unit_load_back( valerie, int, char * );
valerie_error_code valerie_unit_load_back_clipped(valerie,int,char *,long,long)
valerie_error_code valerie_unit_play( valerie, int );
valerie_error_code valerie_unit_play_at_speed( valerie, int, int );
valerie_error_code valerie_unit_stop( valerie, int );
valerie_error_code valerie_unit_pause( valerie, int );
valerie_error_code valerie_unit_rewind( valerie, int );
valerie_error_code valerie_unit_fast_forward( valerie, int );
valerie_error_code valerie_unit_step( valerie, int, int );
valerie_error_code valerie_unit_goto( valerie, int, int );
valerie_error_code valerie_unit_set_in( valerie, int, int );
valerie_error_code valerie_unit_set_out( valerie, int, int );
valerie_error_code valerie_unit_clear_in( valerie, int );
valerie_error_code valerie_unit_clear_out( valerie, int );
valerie_error_code valerie_unit_clear_in_out( valerie, int );
valerie_error_code valerie_unit_set( valerie, int, char *, char * );
valerie_error_code valerie_unit_get( valerie, int, char * );
valerie_error_code valerie_unit_status( valerie, int, valerie_status );
valerie_notifier valerie_get_notifier( valerie );
valerie_dir valerie_dir_init( valerie, char * );
valerie_error_code valerie_dir_get( valerie_dir, int, valerie_dir_entry );
int valerie_dir_count( valerie_dir );
void valerie_dir_close( valerie_dir );
valerie_nodes valerie_nodes_init( valerie );
valerie_error_code valerie_nodes_get(valerie_nodes,int,valerie_node_entry);
int valerie_nodes_count( valerie_nodes );
void valerie_nodes_close( valerie_nodes );
valerie_units valerie_units_init( valerie );
valerie_error_code valerie_units_get(valerie_units,int,valerie_unit_entry);
int valerie_units_count( valerie_units );
void valerie_units_close( valerie_units );
valerie_response valerie_get_last_response( valerie );
valerie_error_code valerie_execute( valerie, size_t, char *, ... );
void valerie_close( valerie );
Notifier Functions
------------------
void valerie_notifier_get( valerie_notifier, valerie_status, int );
void valerie_notifier_put( valerie_notifier, valerie_status );
int valerie_notifier_wait( valerie_notifier, valerie_status );
void valerie_notifier_close( valerie_notifier );
Server Side Queuing
-------------------
valerie_list valerie_list_init( valerie, int )
valerie_error_code valerie_list_get_error_code( valerie_list )
valerie_error_code valerie_list_get( valerie_list, int, valerie_list_entry )
int valerie_list_count( valerie_list )
void valerie_list_close( valerie_list )
valerie_error_code valerie_unit_clean( valerie dv, int unit )
valerie_error_code valerie_unit_append( valerie dv, int unit, char *file, int in, int out )
valerie_error_code valerie_unit_remove_current_clip( valerie dv, int unit )
valerie_error_code valerie_unit_clip_goto( valerie dv, int unit, valerie_clip_offset offset, int clip, int position )
valerie_error_code valerie_unit_clip_set_in( valerie dv, int unit, valerie_clip_offset offset, int clip, int in )
valerie_error_code valerie_unit_clip_set_out( valerie dv, int unit, valerie_clip_offset offset, int clip, int in )
valerie_error_code valerie_unit_clip_move( valerie dv, int unit, valerie_clip_offset offset, int src, valerie_clip_offset offset, int dest )
valerie_error_code valerie_unit_clip_remove( valerie dv, int unit, valerie_clip_offset offset, int clip )
valerie_error_code valerie_unit_clip_insert( valerie dv, int unit, valerie_clip_offset offset, int clip, char *file, int in, int out )
APPENDIX C - COMPLETE LOW LEVEL PARSER API LISTING
--------------------------------------------------
valerie_response valerie_parser_connect( valerie_parser );
valerie_response valerie_parser_execute( valerie_parser, char * );
valerie_response valerie_parser_executef( valerie_parser, char *, ... );
valerie_response valerie_parser_run( valerie_parser, char * );
valerie_notifier valerie_parser_get_notifier( valerie_parser );
void valerie_parser_close( valerie_parser );
valerie_response valerie_response_init( );
valerie_response valerie_response_clone( valerie_response );
int valerie_response_get_error_code( valerie_response );
char *valerie_response_get_error_string( valerie_response );
char *valerie_response_get_line( valerie_response, int );
int valerie_response_count( valerie_response );
void valerie_response_set_error( valerie_response, int, char * );
int valerie_response_printf( valerie_response, size_t, char *, ... );
int valerie_response_write( valerie_response, char *, int );
void valerie_response_close( valerie_response );
APPENDIX D - REFERENCES
-----------------------
(1) doc/dvcp.txt - DVCP protocol
(2) doc/testing.txt - Test procedures

@ -0,0 +1,574 @@
Westley Documentation
Copyright (C) 2004 Ushodaya Enterprised Limited
Authors: Charles Yates <charles.yates@pandora.be>
Last Revision: 2004-03-20
WESTLEY
-------
Preamble:
Westley is the MLT projects XML serialisation/deserialisation format -
as such, it closely mirrors the internal structure of the MLT API.
If you just want to go straight to the DTD, then see
mlt/src/modules/westley/westley.dtd, which gets installed at
$(prefix)/share/mlt/modules/westley.dtd. Currently, the westley parser is
non-validating.
Introduction:
A westley document is essentially a list of 'producers' - a producer is
an mlt object which generates mlt frames (images and associated audio
samples).
There are 3 types of producer:
* Basic Producers - these are typically file or device oriented feeds;
* Playlists - these are arrangements of multiple producers;
* Multitracks - these are the fx encapsulators.
In the mlt model, producers are created and attached to 'consumers' -
consumers are software playback components (such as SDL), or wrappers for
hardware drivers (such as bluefish) or even the westley serialising
consumer itself (the latter doesn't receive frames - it merely
interrogates the connected producer for its configuration).
Although westley was defined as a serialisation mechanism for instantiated
MLT components, this document will concentrate on the hand authoring of
westley documents.
Rules:
As shall become apparent through the remainder of this document, the basic
tenet of westley authoring is to organise the document in the following
manner:
1) create producer elements for each unique media clip in the project;
2) create playlists for each track;
3) create a multitrack and specify filters and transitions;
4) adding global filters.
While other uses of westley exist, the approach taken here is to maximise
efficiency for complex projects.
Basic Producers:
The simplest westley document is:
<westley>
<producer id="producer0">
<property name="resource">clip1.dv</property>
</producer>
</westley>
The westley wrapping is of course superfluous here - loading this document
with MLT is identical to loading the clip directly.
Of course, you can specify additional properties. For example, consider an
MPEG file with multiple soundtracks - you could define a westley document to
ensure that the second audio track is loaded:
<westley>
<producer id="producer0">
<property name="resource">clip1.mpeg</property>
<property name="audio_track">1</property>
</producer>
</westley>
NB: This relies on the mpeg being handled by the avformat producer, rather
than the mcmpeg one. See services.txt for more details.
A more useful example comes with the pango producer for a text producer.
TODO: pango example...
Notes:
1) It is better not to specify in/out points when defining basic producers
as these can be specified in the playlists. The reasoning is that in/out
restricts the amount of the clip available, and could lead to the same clip
being loaded multiple times if you need different regions of the clip
elsewhere;
2) A westley can be specified as a resource, so westleys can naturally
encapsulate other westleys.
Playlists:
Playlists provide a 'collection' structure for producers. These can be used
to define 'tracks' in the multitrack approach, or simple playlists for
sequential, single track playout.
As an example, the following defines two basic producers and a playlist with 3
items:
<westley>
<producer id="producer0">
<property name="resource">clip1.dv</property>
</producer>
<producer id="producer1">
<property name="resource">clip2.dv</property>
</producer>
<playlist id="playlist0">
<entry producer="producer0" in="0" out="2999"/>
<entry producer="producer1" in="0" out="999"/>
<entry producer="producer0" in="3000" out="6999"/>
</playlist>
</westley>
Here we see how the playlist defines the in/out points of the basic
producers.
Notes:
1) All in/out points are absolute frame positions relative to the producer
being appended to the playlist;
2) Westley documents are currently authored for a specific normalisation;
3) The last 'producer' in the document is the default for play out;
4) Playlists can reference the same producer multiple times. In/out regions
do not need to be contiguous - duplication and skipping is acceptable.
Interlude - Introducing Multitracks:
So far we've defined basic producers and playlists/tracks - the tractor is
the element that allows us to arrange our tracks and specify filters and
transitions. Similarly to a playlist, a tractor is a container.
Note that MLT doesn't see a filter or a transition as a producer in the
normal sense - filters and transitions are passive when it comes to seeking.
Internally, seeks are carried out on the producers. This is an important
point - MLT does not follow a traditional graph oriented model.
Visualising an MLT tractor and it's interaction with the consumer will
assist here:
+----------------------------------------------+
|tractor |
| +----------+ +-+ +-+ +-+ +-+ |
| |multitrack| |f| |f| |t| |t| |
| | +------+ | |i| |i| |r| |r| |
| | |track0|-|--->|l|- ->|l|- ->|a|--->|a|\ |
| | +------+ | |t| |t| |n| |n| \ |
| | | |e| |e| |s| |s| \ |
| | +------+ | |r| |r| |i| |i| \ | +--------+
| | |track1|-|- ->|0|--->|1|--->|t|--->|t|-----|--->|consumer|
| | +------+ | | | | | |i| |i| / | +--------+
| | | | | | | |o| |o| / | ^
| | +------+ | | | | | |n| |n| / | |
| | |track2|-|- ->| |- ->| |--->|0|- ->|1|/ | |
| | +------+ | | | | | | | | | | |
| +----------+ +-+ +-+ +-+ +-+ | |
+----------------------------------------------+ |
^ |
| |
+-----------+ |
|APPLICATION|--------------------------------------------+
+-----------+
Internally, all frames from all tracks pass through all the filters and
transitions - these are told which tracks to deal and which regions of the
tracks to work on.
Note that the application communicates with the producer - it can alter
playback speed, position, or even which producer is connected to which
consumer.
The consumer receives the first non-blank frame (see below). It has no say
in the order in which gets them (the sdl consumer when used with inigo might
appear to be an exception - it isn't - it simply has a route back to the
application to allow the application to interpret key presses).
Tractors:
To create a multitrack westley, we can use two playlists and introduce a
tractor. For the purposes of demonstration, I'll add a filter here too:
<westley>
<producer id="producer0">
<property name="resource">clip1.dv</property>
</producer>
<producer id="producer1">
<property name="resource">clip2.dv</property>
</producer>
<playlist id="playlist0">
<entry producer="producer0" in="0" out="2999"/>
<blank length="1000"/>
<entry producer="producer0" in="3000" out="6999"/>
<playlist id="playlist1">
<blank length="3000"/>
<entry producer="producer1" in="0" out="999"/>
</playlist>
<tractor id="tractor0">
<multitrack>
<track producer="playlist0"/>
<track producer="playlist1"/>
</multitrack>
<filter>
<property name="track">0</property>
<property name="mlt_service">greyscale</property>
</filter>
</tractor>
</westley>
Here we see that blank frames are inserted into the first playlist and a
blank is provided at the beginning of the second - this can be visualised in
the traditional timeline widget as follows:
+-------+ +-------------+
|a | |a |
+-------+---+-------------+
|b |
+---+
Adding the filter on the top track, gives us:
+-------+ +-------------+
|a | |a |
+-------+---+-------------+
|greyscale |
--------+---+-------------+
|b |
+---+
Note that it's only applied to the visible parts of the top track.
The requirement to apply a filter to the output, as opposed to a specific
track leads us to the final item in the Rules section above. As an example,
let's assume we wish to watermark all output, then we could use the
following:
<westley>
<producer id="producer0">
<property name="resource">clip1.dv</property>
</producer>
<producer id="producer1">
<property name="resource">clip2.dv</property>
</producer>
<playlist id="playlist0">
<entry producer="producer0" in="0" out="2999"/>
<blank length="1000"/>
<entry producer="producer0" in="3000" out="6999"/>
<playlist id="playlist1">
<blank length="3000"/>
<entry producer="producer1" in="0" out="999"/>
</playlist>
<tractor id="tractor0">
<multitrack>
<track producer="playlist0"/>
<track producer="playlist1"/>
</multitrack>
<filter>
<property name="track">0</property>
<property name="mlt_service">greyscale</property>
</filter>
</tractor>
<tractor id="tractor1">
<multitrack>
<track producer="tractor0"/>
</multitrack>
<filter>
<property name="mlt_service">watermark</property>
<property name="resource">watermark1.png</property>
</filter>
</tractor>
</westley>
Here we employ another tractor and we define a single track (being the
tractor we previously defined) and apply a watermarking filter there.
This is simply provided as an example - the watermarking functionality could
be better handled at the playout stage itself (ie: as a filter automatically
placed between all producers and the consumer).
Tracks act like "layers" in an image processing program like the GIMP. The
bottom-most track takes highest priority and higher layers are overlays
and do not appear unless there are gaps in the lower layers or unless
a transition is applied that merges the tracks on the specifed region.
Practically speaking, for A/B video editing it does not mean too much,
and it will work as expected; however, as a general rule apply any CGI
(graphic overlays with pixbuf or titles with pango) on tracks higher than
your video tracks. Also, this means that any audio-only tracks that are
lower than your video tracks will play rather than the audio from the video
clip. Remember, nothing is affected like mixing or compositing until one
applies a transition or appropriate filter.
<westley>
<producer id="producer0">
<property name="resource">clip1.dv</property>
</producer>
<playlist id="playlist0">
<entry producer="producer0"/>
</playlist>
<producer id="producer1">
<property name="resource">clip2.mpeg</property>
</producer>
<playlist id="playlist1">
<blank length="50"/>
<entry producer="producer1"/>
</playlist>
<tractor id="tractor0" in="0" out="315">
<multitrack id="multitrack0">
<track producer="playlist0"/>
<track producer="playlist1"/>
</multitrack>
<transition id="transition0" in="50" out="74">
<property name="a_track">0</property>
<property name="b_track">1</property>
<property name="mlt_service">luma</property>
</transition>
<transition id="transition1" in="50" out="74">
<property name="a_track">0</property>
<property name="b_track">1</property>
<property name="mlt_service">mix</property>
<property name="start">0.0</property>
<property name="end">1.0</property>
</transition>
</tractor>
</westley>
A "luma" transition is a video wipe processor that takes a greyscale bitmap
for the wipe definition. When one does not specify a bitmap, luma performs
a dissolve. The "mix" transition does an audio mix, but it interpolates
between the gain scaling factors between the start and end properties -
in this example, from 0.0 (none of track B) to 1.0 (all of track B).
Because the bottom track starts out with a gap specified using the <blank>
element, the upper track appears during the blank segment. See the demos and
services.txt to get an idea of the capabilities of the included transitions.
Flexibility:
The information presented above is considered the MLT Westley "normal"
form. This is the output generated by the westley consumer, for example,
when used with inigo. It is the output generated when you use the
"Westley to File" consumer in the demo script, which beginners will find
most useful for learning to use westley XML. This section describes
alternative forms the westley producer accepts.
First of all, the normal form is more of a linear format with producers
and playlists defined prior to their usage in a multitrack. Westley
also accepts a hierarchical format with producers as children of tracks
or playlist entries and with playlists as children of tracks:
<westley>
<tractor>
<multitrack>
<track>
<playlist>
<entry>
<producer>
<property name="resource">clip1.dv</property>
</producer>
</entry>
</playlist>
</track>
</multitrack>
</tractor>
</westley>
Obviously, this example is meant to demonstrate hierarchy and not effective
use of playlist or multitrack!
Secondly, as part of error handling, westley is forgiving if you fail to
supply <tractor>, <track>, and <entry> where one can be understood. This
affords an abbreviated syntax that is less verbose and perhaps less
intimidating for a human to read and understand. One can simplify the
above example as:
<westley>
<multitrack>
<playlist>
<producer>
<property name="resource">clip1.dv</property>
</producer>
</playlist>
</multitrack>
</westley>
Yes, filters and transitions can be added to the above example after the
closing multitrack tag (</multitrack>) because it is still enclosed within
the westley body tags.
If you specify in and out on a producer and it has been enclosed within
an <entry> or <playlist>, then the edit points apply to the playlist
entry and not to the producer itself. This facilitates re-use of media:
<playlist>
<producer id="clip1" in="25" out="78">
<property name="resource">clip1.dv</property>
</producer>
<entry producer="clip1" in="119" out="347"/>
</playlist>
In the above example, the producer attribute of the entry element is
a reference to the preceding producer. All references must follow the
definition. The edit points supplied on the producer above will not affect
the entry that references it below because westley knows the clip is a
playlist entry and optimises this situation. The advantage is that one
does not need to determine every clip to be included ahead of time
and specify them outside the context of the mutlitrack timeline.
This form of authoring will be easier for many to visualise as a non-linear
editor's timeline. Here is a more complex example:
<westley>
<multitrack>
<playlist>
<producer id="foo" in="100" out="149">
<property name="resource">clip2.mpeg</property>
</producer>
<blank length="25"/>
<entry producer="foo" in="10" out="59"/>
</playlist>
<playlist>
<blank length="25"/>
<producer id="bar" in="100" out="199">
<property name="resource">clip3.mpeg</property>
</producer>
<entry out="99" producer="bar"/>
</playlist>
</multitrack>
<filter mlt_service="greyscale" track="0"/>
<transition mlt_service="luma" in="25" out="49" a_track="0" b_track="1"/>
<transition mlt_service="luma" in="75" out="99" a_track="0" b_track="1">
<property name="reverse" value="1"/>
</transition>
</westley>
Did you notice something different in the last example? Properties can be
expressed using XML attributes on the element as well. However, only
non-service-specific properties are supported in this way. For example,
"mlt_service" is available to any producer, filter, or transition. However,
"resource" is actually service-specific. Notice the syntax of the last
property, on the last transition. Westley accepts property values using
the "value" attribute as well as using element text.
We have seen a few different ways of expressing property values. There are
a couple more for properties that can accept XML data. For example, the
GDK pixbuf producer with librsvg can handle embedded SVG, and the Pango
producer can handle embedded Pango markup. You can enclose the embedded XML
using a CDATA section:
<property name="resource"><![CDATA[ <svg>...</svg> ]]></property>
Please ensure the opening CDATA tag immediately follows the opening
property tag and that the section closing tag immediately precedes the
closing property tag.
However, westley can also accept inline embedded XML:
<property name="resource">
<svg>
</svg>
</property>
Currently, there is no namespace handling so a conflict will occur only on
any embedded XML that contains an element named "property" because
westley collects embedded XML until it reaches a closing property tag.
Entities and Parameterisation:
The westley producer parser supports XML entities. An example:
<?xml version="1.0"?>
<!DOCTYPE westley [
<!ENTITY msg "Hello world!">
]>
<westley>
<producer id="producer0">
<property name="mlt_service">pango</property>
<property name="text">&msg;</property>
</producer>
</westley>
If you are embedding another XML document into a property value not using
a CNODE section, then any DOCTYPE section must be relocated before any of
the xml elements to be well-formed. See demo/svg.westley for an example.
Entities can be used to parameterise westley! Using the above example, the
entity declared serves as the default value for &msg;. The entity content
can be overridden from the resource property supplied to the westley
producer. The syntax is the familiar, url-encoded query string used with
HTTP, e.g.: file?name=value&name=value...
There are a couple of rules of usage. The Miracle LOAD command and inigo
command line tool require you to preface the URL with "westley:" because
the query string destroys the filename extension matching peformed by
Fezzik. Also, inigo looks for '=' to tokenise property settings. Therefore,
one uses ':' between name and value instead of '='. Finally, since inigo
is run from the shell, one must enclose the URL within single quotes to
prevent shell filename expansion, or similar.
Needless to say, the ability to parameterise westley XML compositions is
an extremely powerful tool. An example for you to play with is available in
demo/entity.westley. Try overriding the name from inigo:
inigo 'westley:entity.westley?name:Charlie'
Technically, the entity declaration is not needed in the head of the XML
document if you always supply the parameter. However, you run the risk
of unpredictable behviour without one. Therefore, it is safest and a best
practice to always supply an entity declaration. It is improves the
readability as one does not need to search for the entity references to
see what parameters are available.
Tips and Technique:
If one finds the above hierarchical, abbreviated format intuitive,
start with a simple template and fill and extend as needed:
<westley>
<multitrack>
<playlist>
</playlist>
...add a playlist for each track...
</multitrack>
...add filters and transitions...
</westley>
By using a playlist for each track, it is easier to iteratively add new
clips and blank regions as you develop the project. You will not have to
use <track> or later add <playlist> when necessary.
A more advanced template that allows sequencing multitracks is:
<playlist>
<entry>
<multitrack>
<playlist>
</playlist>
...add a playlist for each track...
</multitrack>
...add filters and transitions...
</entry>
<entry>
<multitrack>
<playlist>
</playlist>
...add a playlist for each track...
</multitrack>
...add filters and transitions...
</entry>
</playlist>
If you end up making a collection of templates for various situations, then
consider using XML Entities to make the template more effective by moving
anything that should parameterised into an entity.
If you want to have a silent, black background for audio and video fades,
then make the top track simply <producer mlt_service="colour"/>. Then,
use composite and volume effects. See the "Fade from/to black/silence"
demo for an example (demo/mlt_fade_black).
If you apply the reverse=1 property to a transition like "luma," then
be careful because it also inherently swaps the roles of A and B tracks.
Therefore, you need to might need to swap the a_track and b_track values
if it did not turn out the way you expected. See the "Clock in and out"
for an example (demo/mlt_clock_in_and_out).

@ -0,0 +1,32 @@
export package=framework
export field=0
while [ "$1" != "" ]
do
case $1 in
--help ) field=0 ;;
--version ) field=-1 ;;
--prefix ) field=-2 ;;
--prefix=* ) prefix="${i#--prefix=}" ;;
--cflags ) field=2 ;;
--libs ) field=3 ;;
--list ) field=1; package="" ;;
* ) package=$1 ;;
esac
shift
done
if [ "$field" = "0" ]
then echo "Usage: mlt-config [ --version ] | [ --prefix=dir ] [ [ package ] [ --cflags ] [ --libs ] ]"
elif [ "$field" = "-1" ]
then echo $version
elif [ "$field" = "-2" ]
then config=`which mlt-config`
dir=`dirname $config`
dir=`dirname $dir`
echo $dir
elif [ -f "$prefix/share/mlt/packages.dat" ]
then grep "^$package" $prefix/share/mlt/packages.dat | cut -f $field
else echo mlt-config cannot find package $package.
fi

@ -0,0 +1,14 @@
prefix=/opt/kde3
exec_prefix=/opt/kde3
libdir=/opt/kde3/lib
includedir=/opt/kde3/include
version=0.2.5
cflags=-I/opt/kde3/include -I/opt/kde3/include/mlt -D_REENTRANT
libs=-L/opt/kde3/lib -lmlt
Name: mlt-framework
Description: MLT multimedia framework
Version: ${version}
Requires:
Libs: -L${libdir} ${libs}
Cflags: ${cflags}

@ -0,0 +1,7 @@
Name: mlt-framework
Description: MLT multimedia framework
Version: ${version}
Requires:
Libs: -L${libdir} ${libs}
Cflags: ${cflags}

@ -0,0 +1,14 @@
prefix=/opt/kde3
exec_prefix=/opt/kde3
libdir=/opt/kde3/lib
includedir=/opt/kde3/include
version=0.2.5
cflags=-I/opt/kde3/include/mlt -D_REENTRANT
libs=-L/opt/kde3/lib -lmiracle
Name: mlt-miracle
Description: MLT Miracle server API
Version: ${version}
Requires:
Libs: -L${libdir} ${libs}
Cflags: ${cflags}

@ -0,0 +1,7 @@
Name: mlt-miracle
Description: MLT Miracle server API
Version: ${version}
Requires:
Libs: -L${libdir} ${libs}
Cflags: ${cflags}

@ -0,0 +1,14 @@
prefix=/opt/kde3
exec_prefix=/opt/kde3
libdir=/opt/kde3/lib
includedir=/opt/kde3/include
version=0.2.5
cflags=-I/opt/kde3/include/mlt -D_REENTRANT
libs=-L/opt/kde3/lib -lvalerie
Name: mlt-valerie
Description: MLT Valerie client API
Version: ${version}
Requires:
Libs: -L${libdir} ${libs}
Cflags: ${cflags}

@ -0,0 +1,7 @@
Name: mlt-valerie
Description: MLT Valerie client API
Version: ${version}
Requires:
Libs: -L${libdir} ${libs}
Cflags: ${cflags}

@ -0,0 +1,18 @@
include ../config.mak
all:
depend:
distclean:
clean:
install: all uninstall
install -d "$(DESTDIR)$(prefix)/share/mlt/profiles"
install -m 644 * "$(DESTDIR)$(prefix)/share/mlt/profiles"
rm -f "$(DESTDIR)$(prefix)/share/mlt/profiles/*~"
rm -f "$(DESTDIR)$(prefix)/share/mlt/profiles/Makefile"
uninstall:
rm -rf "$(DESTDIR)$(prefix)/share/mlt/profiles"

@ -0,0 +1,10 @@
description=ATSC 1080i 60Hz
frame_rate_num=30000
frame_rate_den=1001
width=1920
height=1080
progressive=0
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=ATSC 720p 30Hz
frame_rate_num=30000
frame_rate_den=1001
width=1280
height=720
progressive=1
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=CIF NTSC
frame_rate_num=30000
frame_rate_den=1001
width=352
height=288
progressive=1
sample_aspect_num=10
sample_aspect_den=11
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=CIF PAL
frame_rate_num=25
frame_rate_den=1
width=352
height=288
progressive=1
sample_aspect_num=59
sample_aspect_den=54
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=CVD NTSC
frame_rate_num=30000
frame_rate_den=1001
width=352
height=480
progressive=0
sample_aspect_num=20
sample_aspect_den=11
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=CVD PAL
frame_rate_num=25
frame_rate_den=1
width=352
height=576
progressive=0
sample_aspect_num=59
sample_aspect_den=27
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=DV NTSC
frame_rate_num=30000
frame_rate_den=1001
width=720
height=480
progressive=0
sample_aspect_num=10
sample_aspect_den=11
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=DV NTSC Widescreen
frame_rate_num=30000
frame_rate_den=1001
width=720
height=480
progressive=0
sample_aspect_num=40
sample_aspect_den=33
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=DV PAL
frame_rate_num=25
frame_rate_den=1
width=720
height=576
progressive=0
sample_aspect_num=59
sample_aspect_den=54
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=DV PAL Widescreen
frame_rate_num=25
frame_rate_den=1
width=720
height=576
progressive=0
sample_aspect_num=118
sample_aspect_den=81
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=HDV 1080 50i
frame_rate_num=25
frame_rate_den=1
width=1440
height=1080
progressive=0
sample_aspect_num=4
sample_aspect_den=3
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=HDV 1080 60i
frame_rate_num=30000
frame_rate_den=1001
width=1440
height=1080
progressive=0
sample_aspect_num=4
sample_aspect_den=3
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=HDV 720 25p
frame_rate_num=25
frame_rate_den=1
width=1280
height=720
progressive=1
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=HDV 720 30p
frame_rate_num=30000
frame_rate_den=1001
width=1280
height=720
progressive=1
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=QCIF NTSC
frame_rate_num=30000
frame_rate_den=1001
width=176
height=144
progressive=1
sample_aspect_num=10
sample_aspect_den=11
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=QCIF PAL
frame_rate_num=25
frame_rate_den=1
width=176
height=144
progressive=1
sample_aspect_num=59
sample_aspect_den=54
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=Quarter Square NTSC
frame_rate_num=30000
frame_rate_den=1001
width=320
height=240
progressive=1
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=Quarter Square NTSC Widescreen
frame_rate_num=30000
frame_rate_den=1001
width=426
height=240
progressive=1
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=Quarter Square PAL
frame_rate_num=25
frame_rate_den=1
width=384
height=288
progressive=1
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=Quarter Square PAL Widescreen
frame_rate_num=25
frame_rate_den=1
width=512
height=288
progressive=1
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=Square NTSC
frame_rate_num=30000
frame_rate_den=1001
width=640
height=480
progressive=1
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=Square NTSC Widescreen
frame_rate_num=30000
frame_rate_den=1001
width=854
height=480
progressive=1
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=Square PAL
frame_rate_num=25
frame_rate_den=1
width=768
height=576
progressive=1
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=Square PAL Widescreen
frame_rate_num=25
frame_rate_den=1
width=1024
height=576
progressive=1
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=SVCD NTSC
frame_rate_num=30000
frame_rate_den=1001
width=480
height=480
progressive=0
sample_aspect_num=15
sample_aspect_den=11
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=SVCD NTSC Widescreen
frame_rate_num=30000
frame_rate_den=1001
width=480
height=480
progressive=0
sample_aspect_num=20
sample_aspect_den=11
display_aspect_num=16
display_aspect_den=9

@ -0,0 +1,10 @@
description=SVCD PAL
frame_rate_num=25
frame_rate_den=1
width=480
height=576
progressive=0
sample_aspect_num=59
sample_aspect_den=36
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=SVCD PAL Widescreen
frame_rate_num=25
frame_rate_den=1
width=480
height=576
progressive=0
sample_aspect_num=59
sample_aspect_den=27
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=VCD NTSC
frame_rate_num=30000
frame_rate_den=1001
width=352
height=240
progressive=1
sample_aspect_num=10
sample_aspect_den=11
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,10 @@
description=VCD PAL
frame_rate_num=25
frame_rate_den=1
width=352
height=288
progressive=1
sample_aspect_num=59
sample_aspect_den=54
display_aspect_num=4
display_aspect_den=3

@ -0,0 +1,25 @@
# Environment variable settings to allow execution without install
export MLT_REPOSITORY=`pwd`/src/modules
export MLT_PROFILES_PATH=`pwd`/profiles
export LD_LIBRARY_PATH=\
`pwd`/src/framework:\
`pwd`/src/valerie:\
`pwd`/src/miracle:\
`pwd`/src/modules/bluefish:\
`pwd`/../BlueLinuxDriver/install/lib:\
`pwd`/../mpeg_sdk_release/bin:\
`pwd`/../dvcpro_sdk_release/lib:\
`pwd`/../sr_sdk_release:\
$LD_LIBRARY_PATH
[ $(uname -s) = Darwin ] && export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
export PATH=\
`pwd`/src/albino:\
`pwd`/src/inigo:\
`pwd`/src/humperdink:\
`pwd`/src/miracle:\
$PATH

@ -0,0 +1,9 @@
# Environment variable settings to allow execution without install
export LD_LIBRARY_PATH=\
`pwd`/../mpeg_sdk_release/bin:\
`pwd`/../dvcpro_sdk_release/lib:\
`pwd`/../sr_sdk_release/lib:\
$LD_LIBRARY_PATH

@ -0,0 +1,36 @@
include ../../config.mak
TARGET = albino
OBJS = albino.o
CFLAGS += -I.. $(RDYNAMIC)
LDFLAGS += -L../miracle -lmiracle -L../valerie -lvalerie -L../miracle -lmiracle -L../framework -lmlt
SRCS := $(OBJS:.o=.c)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) -o $@ $(OBJS) $(LDFLAGS)
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $^ 1>.depend
distclean: clean
rm -f .depend
clean:
rm -f $(OBJS) $(TARGET)
install: all
install -d "$(DESTDIR)$(bindir)"
install -c -s -m 755 $(TARGET) "$(DESTDIR)$(bindir)"
uninstall:
rm -f "$(DESTDIR)$(bindir)/$(TARGET)"
ifneq ($(wildcard .depend),)
include .depend
endif

@ -0,0 +1,110 @@
/*
* albino.c -- Local Valerie/Miracle Test Utility
* Copyright (C) 2002-2003 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* System header files */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
/* Application header files */
#include <miracle/miracle_local.h>
#include <valerie/valerie_remote.h>
#include <valerie/valerie_util.h>
char *prompt( char *command, int length )
{
printf( "> " );
return fgets( command, length, stdin );
}
void report( valerie_response response )
{
int index = 0;
if ( response != NULL )
for ( index = 0; index < valerie_response_count( response ); index ++ )
printf( "%4d: %s\n", index, valerie_response_get_line( response, index ) );
}
int main( int argc, char **argv )
{
valerie_parser parser = NULL;
valerie_response response = NULL;
char temp[ 1024 ];
int index = 1;
if ( argc > 2 && !strcmp( argv[ 1 ], "-s" ) )
{
printf( "Miracle Client Instance\n" );
parser = valerie_parser_init_remote( argv[ 2 ], 5250 );
response = valerie_parser_connect( parser );
index = 3;
}
else
{
struct sched_param scp;
// Use realtime scheduling if possible
memset( &scp, '\0', sizeof( scp ) );
scp.sched_priority = sched_get_priority_max( SCHED_FIFO ) - 1;
#ifndef __DARWIN__
sched_setscheduler( 0, SCHED_FIFO, &scp );
#endif
printf( "Miracle Standalone Instance\n" );
parser = miracle_parser_init_local( );
response = valerie_parser_connect( parser );
}
if ( response != NULL )
{
/* process files on command lines before going into console mode */
for ( ; index < argc; index ++ )
{
valerie_response_close( response );
response = valerie_parser_run( parser, argv[ index ] );
report( response );
}
while ( response != NULL && prompt( temp, 1024 ) )
{
valerie_util_trim( valerie_util_chomp( temp ) );
if ( !strcasecmp( temp, "BYE" ) )
{
break;
}
else if ( strcmp( temp, "" ) )
{
valerie_response_close( response );
response = valerie_parser_execute( parser, temp );
report( response );
}
}
}
else
{
fprintf( stderr, "Unable to connect to a Miracle instance.\n" );
}
printf( "\n" );
valerie_parser_close( parser );
return 0;
}

@ -0,0 +1,97 @@
include ../../config.mak
NAME = libmlt$(LIBSUF)
TARGET = $(NAME).$(version)
ifneq ($(targetos), Darwin)
NAME = libmlt$(LIBSUF)
TARGET = $(NAME).$(version)
SHFLAGS += -Wl,-soname,$(TARGET)
else
NAME = libmlt$(LIBSUF)
TARGET = libmlt.$(version)$(LIBSUF)
SHFLAGS += -install_name $(libdir)/$(TARGET)
endif
OBJS = mlt_frame.o \
mlt_geometry.o \
mlt_deque.o \
mlt_property.o \
mlt_properties.o \
mlt_events.o \
mlt_parser.o \
mlt_service.o \
mlt_producer.o \
mlt_multitrack.o \
mlt_playlist.o \
mlt_consumer.o \
mlt_filter.o \
mlt_transition.o \
mlt_field.o \
mlt_tractor.o \
mlt_factory.o \
mlt_repository.o \
mlt_pool.o \
mlt_tokeniser.o \
mlt_profile.o
INCS = mlt_consumer.h \
mlt_factory.h \
mlt_filter.h \
mlt.h \
mlt_multitrack.h \
mlt_pool.h \
mlt_properties.h \
mlt_events.h \
mlt_parser.h \
mlt_repository.h \
mlt_tractor.h \
mlt_types.h \
mlt_deque.h \
mlt_field.h \
mlt_frame.h \
mlt_geometry.h \
mlt_playlist.h \
mlt_producer.h \
mlt_property.h \
mlt_service.h \
mlt_transition.h \
mlt_tokeniser.h \
mlt_profile.h
SRCS := $(OBJS:.o=.c)
CFLAGS += $(RDYNAMIC) -DPREFIX="\"$(prefix)\""
LDFLAGS += -lm $(LIBDL) -lpthread
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS)
ln -sf $(TARGET) $(NAME)
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $^ 1>.depend
distclean: clean
rm -f .depend
clean:
rm -f $(OBJS) $(TARGET) $(NAME)
install:
install -d $(DESTDIR)$(libdir)
install -m 755 $(TARGET) $(DESTDIR)$(libdir)
ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(NAME)
install -d "$(DESTDIR)$(prefix)/include/mlt/framework"
install -m 644 $(INCS) "$(DESTDIR)$(prefix)/include/mlt/framework"
uninstall:
rm -f "$(DESTDIR)$(libdir)/$(TARGET)"
rm -f "$(DESTDIR)$(libdir)/$(NAME)"
rm -rf "$(DESTDIR)$(prefix)/include/mlt/framework"
ifneq ($(wildcard .depend),)
include .depend
endif

@ -0,0 +1,9 @@
/** GENERATED FILE - DON'T EDIT */
#ifndef _MLT_CONFIG_H_
#define _MLT_CONFIG_H_
#define PREFIX_DATA PREFIX "/lib/mlt/modules"
#endif

@ -0,0 +1,2 @@
#!/bin/sh
echo "framework -I$prefix/include -I$prefix/include/mlt -D_REENTRANT -L$libdir -lmlt" >> ../../packages.dat

@ -0,0 +1,51 @@
/*
* mlt.h -- header file for lazy client and implementation code :-)
* Copyright (C) 2003-2004 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MLT_H_
#define _MLT_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include "mlt_factory.h"
#include "mlt_frame.h"
#include "mlt_deque.h"
#include "mlt_multitrack.h"
#include "mlt_producer.h"
#include "mlt_transition.h"
#include "mlt_consumer.h"
#include "mlt_filter.h"
#include "mlt_playlist.h"
#include "mlt_properties.h"
#include "mlt_field.h"
#include "mlt_tractor.h"
#include "mlt_tokeniser.h"
#include "mlt_parser.h"
#include "mlt_geometry.h"
#include "mlt_profile.h"
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,797 @@
/*
* mlt_consumer.c -- abstraction for all consumer services
* Copyright (C) 2003-2004 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "mlt_consumer.h"
#include "mlt_factory.h"
#include "mlt_producer.h"
#include "mlt_frame.h"
#include "mlt_profile.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service this, void **args );
static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service this, void **args );
static void mlt_consumer_property_changed( mlt_service owner, mlt_consumer this, char *name );
static void apply_profile_properties( mlt_profile profile, mlt_properties properties );
static mlt_event g_event_listener = NULL;
/** Public final methods
*/
int mlt_consumer_init( mlt_consumer this, void *child )
{
int error = 0;
memset( this, 0, sizeof( struct mlt_consumer_s ) );
this->child = child;
error = mlt_service_init( &this->parent, this );
if ( error == 0 )
{
// Get the properties from the service
mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent );
// Apply the profile to properties for legacy integration
apply_profile_properties( mlt_profile_get(), properties );
// Default rescaler for all consumers
mlt_properties_set( properties, "rescale", "bilinear" );
// Default read ahead buffer size
mlt_properties_set_int( properties, "buffer", 25 );
// Default audio frequency and channels
mlt_properties_set_int( properties, "frequency", 48000 );
mlt_properties_set_int( properties, "channels", 2 );
// Default of all consumers is real time
mlt_properties_set_int( properties, "real_time", 1 );
// Default to environment test card
mlt_properties_set( properties, "test_card", mlt_environment( "MLT_TEST_CARD" ) );
// Hmm - default all consumers to yuv422 :-/
this->format = mlt_image_yuv422;
mlt_events_register( properties, "consumer-frame-show", ( mlt_transmitter )mlt_consumer_frame_show );
mlt_events_register( properties, "consumer-frame-render", ( mlt_transmitter )mlt_consumer_frame_render );
mlt_events_register( properties, "consumer-stopped", NULL );
// Register a property-changed listener to handle the profile property -
// subsequent properties can override the profile
g_event_listener = mlt_events_listen( properties, this, "property-changed", ( mlt_listener )mlt_consumer_property_changed );
// Create the push mutex and condition
pthread_mutex_init( &this->put_mutex, NULL );
pthread_cond_init( &this->put_cond, NULL );
}
return error;
}
static void apply_profile_properties( mlt_profile profile, mlt_properties properties )
{
mlt_event_block( g_event_listener );
mlt_properties_set_double( properties, "fps", mlt_profile_fps( profile ) );
mlt_properties_set_int( properties, "frame_rate_num", profile->frame_rate_num );
mlt_properties_set_int( properties, "frame_rate_den", profile->frame_rate_den );
mlt_properties_set_int( properties, "width", profile->width );
mlt_properties_set_int( properties, "height", profile->height );
mlt_properties_set_int( properties, "progressive", profile->progressive );
mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) );
mlt_properties_set_int( properties, "sample_aspect_num", profile->sample_aspect_num );
mlt_properties_set_int( properties, "sample_aspect_den", profile->sample_aspect_den );
mlt_properties_set_double( properties, "display_ratio", mlt_profile_dar( profile ) );
mlt_properties_set_int( properties, "display_aspect_num", profile->display_aspect_num );
mlt_properties_set_int( properties, "display_aspect_num", profile->display_aspect_num );
mlt_event_unblock( g_event_listener );
}
static void mlt_consumer_property_changed( mlt_service owner, mlt_consumer this, char *name )
{
if ( !strcmp( name, "profile" ) )
{
// Get the properies
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
// Locate the profile
mlt_profile_select( mlt_properties_get( properties, "profile" ) );
// Apply to properties
apply_profile_properties( mlt_profile_get(), properties );
}
else if ( !strcmp( name, "frame_rate_num" ) )
{
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
mlt_profile_get()->frame_rate_num = mlt_properties_get_int( properties, "frame_rate_num" );
mlt_properties_set_double( properties, "fps", mlt_profile_fps( NULL ) );
}
else if ( !strcmp( name, "frame_rate_den" ) )
{
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
mlt_profile_get()->frame_rate_den = mlt_properties_get_int( properties, "frame_rate_den" );
mlt_properties_set_double( properties, "fps", mlt_profile_fps( NULL ) );
}
else if ( !strcmp( name, "width" ) )
{
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
mlt_profile_get()->width = mlt_properties_get_int( properties, "width" );
}
else if ( !strcmp( name, "height" ) )
{
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
mlt_profile_get()->height = mlt_properties_get_int( properties, "height" );
}
else if ( !strcmp( name, "progressive" ) )
{
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
mlt_profile_get()->progressive = mlt_properties_get_int( properties, "progressive" );
}
else if ( !strcmp( name, "sample_aspect_num" ) )
{
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
mlt_profile_get()->sample_aspect_num = mlt_properties_get_int( properties, "sample_aspect_num" );
mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( NULL ) );
}
else if ( !strcmp( name, "sample_aspect_den" ) )
{
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
mlt_profile_get()->sample_aspect_den = mlt_properties_get_int( properties, "sample_aspect_den" );
mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( NULL ) );
}
else if ( !strcmp( name, "display_aspect_num" ) )
{
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
mlt_profile_get()->display_aspect_num = mlt_properties_get_int( properties, "display_aspect_num" );
mlt_properties_set_double( properties, "display_ratio", mlt_profile_dar( NULL ) );
}
else if ( !strcmp( name, "display_aspect_den" ) )
{
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
mlt_profile_get()->display_aspect_den = mlt_properties_get_int( properties, "display_aspect_den" );
mlt_properties_set_double( properties, "display_ratio", mlt_profile_dar( NULL ) );
}
}
static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service this, void **args )
{
if ( listener != NULL )
listener( owner, this, ( mlt_frame )args[ 0 ] );
}
static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service this, void **args )
{
if ( listener != NULL )
listener( owner, this, ( mlt_frame )args[ 0 ] );
}
/** Create a new consumer.
*/
mlt_consumer mlt_consumer_new( )
{
// Create the memory for the structure
mlt_consumer this = malloc( sizeof( struct mlt_consumer_s ) );
// Initialise it
if ( this != NULL )
mlt_consumer_init( this, NULL );
// Return it
return this;
}
/** Get the parent service object.
*/
mlt_service mlt_consumer_service( mlt_consumer this )
{
return this != NULL ? &this->parent : NULL;
}
/** Get the consumer properties.
*/
mlt_properties mlt_consumer_properties( mlt_consumer this )
{
return this != NULL ? MLT_SERVICE_PROPERTIES( &this->parent ) : NULL;
}
/** Connect the consumer to the producer.
*/
int mlt_consumer_connect( mlt_consumer this, mlt_service producer )
{
return mlt_service_connect_producer( &this->parent, producer, 0 );
}
/** Start the consumer.
*/
int mlt_consumer_start( mlt_consumer this )
{
// Stop listening to the property-changed event
mlt_event_block( g_event_listener );
// Get the properies
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
// Determine if there's a test card producer
char *test_card = mlt_properties_get( properties, "test_card" );
// Just to make sure nothing is hanging around...
mlt_frame_close( this->put );
this->put = NULL;
this->put_active = 1;
// Deal with it now.
if ( test_card != NULL )
{
if ( mlt_properties_get_data( properties, "test_card_producer", NULL ) == NULL )
{
// Create a test card producer
mlt_producer producer = mlt_factory_producer( NULL, test_card );
// Do we have a producer
if ( producer != NULL )
{
// Test card should loop I guess...
mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" );
//mlt_producer_set_speed( producer, 0 );
//mlt_producer_set_in_and_out( producer, 0, 0 );
// Set the test card on the consumer
mlt_properties_set_data( properties, "test_card_producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL );
}
}
}
else
{
// Allow the hash table to speed things up
mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
}
// Check and run an ante command
if ( mlt_properties_get( properties, "ante" ) )
system( mlt_properties_get( properties, "ante" ) );
// Set the real_time preference
this->real_time = mlt_properties_get_int( properties, "real_time" );
// Start the service
if ( this->start != NULL )
return this->start( this );
return 0;
}
/** An alternative method to feed frames into the consumer - only valid if
the consumer itself is not connected.
*/
int mlt_consumer_put_frame( mlt_consumer this, mlt_frame frame )
{
int error = 1;
// Get the service assoicated to the consumer
mlt_service service = MLT_CONSUMER_SERVICE( this );
if ( mlt_service_producer( service ) == NULL )
{
struct timeval now;
struct timespec tm;
pthread_mutex_lock( &this->put_mutex );
while ( this->put_active && this->put != NULL )
{
gettimeofday( &now, NULL );
tm.tv_sec = now.tv_sec + 1;
tm.tv_nsec = now.tv_usec * 1000;
pthread_cond_timedwait( &this->put_cond, &this->put_mutex, &tm );
}
if ( this->put_active && this->put == NULL )
this->put = frame;
else
mlt_frame_close( frame );
pthread_cond_broadcast( &this->put_cond );
pthread_mutex_unlock( &this->put_mutex );
}
else
{
mlt_frame_close( frame );
}
return error;
}
/** Protected method for consumer to get frames from connected service
*/
mlt_frame mlt_consumer_get_frame( mlt_consumer this )
{
// Frame to return
mlt_frame frame = NULL;
// Get the service assoicated to the consumer
mlt_service service = MLT_CONSUMER_SERVICE( this );
// Get the consumer properties
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
// Get the frame
if ( mlt_service_producer( service ) == NULL && mlt_properties_get_int( properties, "put_mode" ) )
{
struct timeval now;
struct timespec tm;
pthread_mutex_lock( &this->put_mutex );
while ( this->put_active && this->put == NULL )
{
gettimeofday( &now, NULL );
tm.tv_sec = now.tv_sec + 1;
tm.tv_nsec = now.tv_usec * 1000;
pthread_cond_timedwait( &this->put_cond, &this->put_mutex, &tm );
}
frame = this->put;
this->put = NULL;
pthread_cond_broadcast( &this->put_cond );
pthread_mutex_unlock( &this->put_mutex );
if ( frame != NULL )
mlt_service_apply_filters( service, frame, 0 );
}
else if ( mlt_service_producer( service ) != NULL )
{
mlt_service_get_frame( service, &frame, 0 );
}
else
{
frame = mlt_frame_init( );
}
if ( frame != NULL )
{
// Get the frame properties
mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
// Get the test card producer
mlt_producer test_card = mlt_properties_get_data( properties, "test_card_producer", NULL );
// Attach the test frame producer to it.
if ( test_card != NULL )
mlt_properties_set_data( frame_properties, "test_card_producer", test_card, 0, NULL, NULL );
// Attach the rescale property
mlt_properties_set( frame_properties, "rescale.interp", mlt_properties_get( properties, "rescale" ) );
// Aspect ratio and other jiggery pokery
mlt_properties_set_double( frame_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "aspect_ratio" ) );
mlt_properties_set_int( frame_properties, "consumer_deinterlace", mlt_properties_get_int( properties, "progressive" ) | mlt_properties_get_int( properties, "deinterlace" ) );
mlt_properties_set( frame_properties, "deinterlace_method", mlt_properties_get( properties, "deinterlace_method" ) );
}
// Return the frame
return frame;
}
static inline long time_difference( struct timeval *time1 )
{
struct timeval time2;
time2.tv_sec = time1->tv_sec;
time2.tv_usec = time1->tv_usec;
gettimeofday( time1, NULL );
return time1->tv_sec * 1000000 + time1->tv_usec - time2.tv_sec * 1000000 - time2.tv_usec;
}
int mlt_consumer_profile( mlt_properties properties, char *profile )
{
mlt_profile p = mlt_profile_select( profile );
if ( p )
{
apply_profile_properties( p, properties );
return 1;
}
else
{
return 0;
}
}
static void *consumer_read_ahead_thread( void *arg )
{
// The argument is the consumer
mlt_consumer this = arg;
// Get the properties of the consumer
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
// Get the width and height
int width = mlt_properties_get_int( properties, "width" );
int height = mlt_properties_get_int( properties, "height" );
// See if video is turned off
int video_off = mlt_properties_get_int( properties, "video_off" );
int preview_off = mlt_properties_get_int( properties, "preview_off" );
int preview_format = mlt_properties_get_int( properties, "preview_format" );
// Get the audio settings
mlt_audio_format afmt = mlt_audio_pcm;
int counter = 0;
double fps = mlt_properties_get_double( properties, "fps" );
int channels = mlt_properties_get_int( properties, "channels" );
int frequency = mlt_properties_get_int( properties, "frequency" );
int samples = 0;
int16_t *pcm = NULL;
// See if audio is turned off
int audio_off = mlt_properties_get_int( properties, "audio_off" );
// Get the maximum size of the buffer
int buffer = mlt_properties_get_int( properties, "buffer" ) + 1;
// General frame variable
mlt_frame frame = NULL;
uint8_t *image = NULL;
// Time structures
struct timeval ante;
// Average time for get_frame and get_image
int count = 1;
int skipped = 0;
int64_t time_wait = 0;
int64_t time_frame = 0;
int64_t time_process = 0;
int skip_next = 0;
mlt_service lock_object = NULL;
if ( preview_off && preview_format != 0 )
this->format = preview_format;
// Get the first frame
frame = mlt_consumer_get_frame( this );
// Get the lock object
lock_object = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "consumer_lock_service", NULL );
// Lock it
if ( lock_object ) mlt_service_lock( lock_object );
// Get the image of the first frame
if ( !video_off )
{
mlt_events_fire( MLT_CONSUMER_PROPERTIES( this ), "consumer-frame-render", frame, NULL );
mlt_frame_get_image( frame, &image, &this->format, &width, &height, 0 );
}
if ( !audio_off )
{
samples = mlt_sample_calculator( fps, frequency, counter++ );
mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples );
}
// Unlock the lock object
if ( lock_object ) mlt_service_unlock( lock_object );
// Mark as rendered
mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 );
// Get the starting time (can ignore the times above)
gettimeofday( &ante, NULL );
// Continue to read ahead
while ( this->ahead )
{
// Fetch width/height again
width = mlt_properties_get_int( properties, "width" );
height = mlt_properties_get_int( properties, "height" );
// Put the current frame into the queue
pthread_mutex_lock( &this->mutex );
while( this->ahead && mlt_deque_count( this->queue ) >= buffer )
pthread_cond_wait( &this->cond, &this->mutex );
mlt_deque_push_back( this->queue, frame );
pthread_cond_broadcast( &this->cond );
pthread_mutex_unlock( &this->mutex );
time_wait += time_difference( &ante );
// Get the next frame
frame = mlt_consumer_get_frame( this );
time_frame += time_difference( &ante );
// If there's no frame, we're probably stopped...
if ( frame == NULL )
continue;
// Attempt to fetch the lock object
lock_object = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "consumer_lock_service", NULL );
// Increment the count
count ++;
// Lock if there's a lock object
if ( lock_object ) mlt_service_lock( lock_object );
// All non normal playback frames should be shown
if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "_speed" ) != 1 )
{
mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 );
skipped = 0;
time_frame = 0;
time_process = 0;
time_wait = 0;
count = 1;
skip_next = 0;
}
// Get the image
if ( !skip_next )
{
// Get the image, mark as rendered and time it
if ( !video_off )
{
mlt_events_fire( MLT_CONSUMER_PROPERTIES( this ), "consumer-frame-render", frame, NULL );
mlt_frame_get_image( frame, &image, &this->format, &width, &height, 0 );
}
mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 );
}
else
{
// Increment the number of sequentially skipped frames
skipped ++;
skip_next = 0;
// If we've reached an unacceptable level, reset everything
if ( skipped > 5 )
{
skipped = 0;
time_frame = 0;
time_process = 0;
time_wait = 0;
count = 1;
}
}
// Always process audio
if ( !audio_off )
{
samples = mlt_sample_calculator( fps, frequency, counter++ );
mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples );
}
// Increment the time take for this frame
time_process += time_difference( &ante );
// Determine if the next frame should be skipped
if ( mlt_deque_count( this->queue ) <= 5 && ( ( time_wait + time_frame + time_process ) / count ) > 40000 )
skip_next = 1;
// Unlock if there's a lock object
if ( lock_object ) mlt_service_unlock( lock_object );
}
// Remove the last frame
mlt_frame_close( frame );
return NULL;
}
static void consumer_read_ahead_start( mlt_consumer this )
{
// We're running now
this->ahead = 1;
// Create the frame queue
this->queue = mlt_deque_init( );
// Create the mutex
pthread_mutex_init( &this->mutex, NULL );
// Create the condition
pthread_cond_init( &this->cond, NULL );
// Create the read ahead
pthread_create( &this->ahead_thread, NULL, consumer_read_ahead_thread, this );
}
static void consumer_read_ahead_stop( mlt_consumer this )
{
// Make sure we're running
if ( this->ahead )
{
// Inform thread to stop
this->ahead = 0;
// Broadcast to the condition in case it's waiting
pthread_mutex_lock( &this->mutex );
pthread_cond_broadcast( &this->cond );
pthread_mutex_unlock( &this->mutex );
// Broadcast to the put condition in case it's waiting
pthread_mutex_lock( &this->put_mutex );
pthread_cond_broadcast( &this->put_cond );
pthread_mutex_unlock( &this->put_mutex );
// Join the thread
pthread_join( this->ahead_thread, NULL );
// Destroy the mutex
pthread_mutex_destroy( &this->mutex );
// Destroy the condition
pthread_cond_destroy( &this->cond );
// Wipe the queue
while ( mlt_deque_count( this->queue ) )
mlt_frame_close( mlt_deque_pop_back( this->queue ) );
// Close the queue
mlt_deque_close( this->queue );
}
}
void mlt_consumer_purge( mlt_consumer this )
{
if ( this->ahead )
{
pthread_mutex_lock( &this->mutex );
while ( mlt_deque_count( this->queue ) )
mlt_frame_close( mlt_deque_pop_back( this->queue ) );
pthread_cond_broadcast( &this->cond );
pthread_mutex_unlock( &this->mutex );
}
}
mlt_frame mlt_consumer_rt_frame( mlt_consumer this )
{
// Frame to return
mlt_frame frame = NULL;
// Get the properties
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
// Check if the user has requested real time or not
if ( this->real_time )
{
int size = 1;
// Is the read ahead running?
if ( this->ahead == 0 )
{
int buffer = mlt_properties_get_int( properties, "buffer" );
int prefill = mlt_properties_get_int( properties, "prefill" );
consumer_read_ahead_start( this );
if ( buffer > 1 )
size = prefill > 0 && prefill < buffer ? prefill : buffer;
}
// Get frame from queue
pthread_mutex_lock( &this->mutex );
while( this->ahead && mlt_deque_count( this->queue ) < size )
pthread_cond_wait( &this->cond, &this->mutex );
frame = mlt_deque_pop_front( this->queue );
pthread_cond_broadcast( &this->cond );
pthread_mutex_unlock( &this->mutex );
}
else
{
// Get the frame in non real time
frame = mlt_consumer_get_frame( this );
// This isn't true, but from the consumers perspective it is
if ( frame != NULL )
mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 );
}
return frame;
}
/** Callback for the implementation to indicate a stopped condition.
*/
void mlt_consumer_stopped( mlt_consumer this )
{
mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( this ), "running", 0 );
mlt_events_fire( MLT_CONSUMER_PROPERTIES( this ), "consumer-stopped", NULL );
mlt_event_unblock( g_event_listener );
}
/** Stop the consumer.
*/
int mlt_consumer_stop( mlt_consumer this )
{
// Get the properies
mlt_properties properties = MLT_CONSUMER_PROPERTIES( this );
char *debug = mlt_properties_get( MLT_CONSUMER_PROPERTIES( this ), "debug" );
// Just in case...
if ( debug ) fprintf( stderr, "%s: stopping put waiting\n", debug );
pthread_mutex_lock( &this->put_mutex );
this->put_active = 0;
pthread_cond_broadcast( &this->put_cond );
pthread_mutex_unlock( &this->put_mutex );
// Stop the consumer
if ( debug ) fprintf( stderr, "%s: stopping consumer\n", debug );
if ( this->stop != NULL )
this->stop( this );
// Check if the user has requested real time or not and stop if necessary
if ( debug ) fprintf( stderr, "%s: stopping read_ahead\n", debug );
if ( mlt_properties_get_int( properties, "real_time" ) )
consumer_read_ahead_stop( this );
// Kill the test card
mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
// Check and run a post command
if ( mlt_properties_get( properties, "post" ) )
system( mlt_properties_get( properties, "post" ) );
if ( debug ) fprintf( stderr, "%s: stopped\n", debug );
return 0;
}
/** Determine if the consumer is stopped.
*/
int mlt_consumer_is_stopped( mlt_consumer this )
{
// Check if the consumer is stopped
if ( this->is_stopped != NULL )
return this->is_stopped( this );
return 0;
}
/** Close the consumer.
*/
void mlt_consumer_close( mlt_consumer this )
{
if ( this != NULL && mlt_properties_dec_ref( MLT_CONSUMER_PROPERTIES( this ) ) <= 0 )
{
// Get the childs close function
void ( *consumer_close )( ) = this->close;
if ( consumer_close )
{
// Just in case...
//mlt_consumer_stop( this );
this->close = NULL;
consumer_close( this );
}
else
{
// Make sure it only gets called once
this->parent.close = NULL;
// Destroy the push mutex and condition
pthread_mutex_destroy( &this->put_mutex );
pthread_cond_destroy( &this->put_cond );
mlt_service_close( &this->parent );
}
}
}

@ -0,0 +1,80 @@
/*
* mlt_consumer.h -- abstraction for all consumer services
* Copyright (C) 2003-2004 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MLT_CONSUMER_H_
#define _MLT_CONSUMER_H_
#include "mlt_service.h"
#include <pthread.h>
/** The interface definition for all consumers.
*/
struct mlt_consumer_s
{
/* We're implementing service here */
struct mlt_service_s parent;
/* public virtual */
int ( *start )( mlt_consumer );
int ( *stop )( mlt_consumer );
int ( *is_stopped )( mlt_consumer );
void ( *close )( mlt_consumer );
/* Private data */
void *local;
void *child;
int real_time;
int ahead;
mlt_image_format format;
mlt_deque queue;
pthread_t ahead_thread;
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_mutex_t put_mutex;
pthread_cond_t put_cond;
mlt_frame put;
int put_active;
};
/** Public final methods
*/
#define MLT_CONSUMER_SERVICE( consumer ) ( &( consumer )->parent )
#define MLT_CONSUMER_PROPERTIES( consumer ) MLT_SERVICE_PROPERTIES( MLT_CONSUMER_SERVICE( consumer ) )
extern int mlt_consumer_init( mlt_consumer self, void *child );
extern mlt_consumer mlt_consumer_new( );
extern mlt_service mlt_consumer_service( mlt_consumer self );
extern mlt_properties mlt_consumer_properties( mlt_consumer self );
extern int mlt_consumer_connect( mlt_consumer self, mlt_service producer );
extern int mlt_consumer_start( mlt_consumer self );
extern void mlt_consumer_purge( mlt_consumer self );
extern int mlt_consumer_put_frame( mlt_consumer self, mlt_frame frame );
extern mlt_frame mlt_consumer_get_frame( mlt_consumer self );
extern mlt_frame mlt_consumer_rt_frame( mlt_consumer self );
extern int mlt_consumer_stop( mlt_consumer self );
extern int mlt_consumer_is_stopped( mlt_consumer self );
extern void mlt_consumer_stopped( mlt_consumer self );
extern void mlt_consumer_close( mlt_consumer );
extern int mlt_consumer_profile( mlt_properties properties, char *profile );
#endif

@ -0,0 +1,297 @@
/*
* mlt_deque.c -- double ended queue
* Copyright (C) 2003-2004 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
// Local header files
#include "mlt_deque.h"
// System header files
#include <stdlib.h>
#include <string.h>
typedef union
{
void *addr;
int value;
double floating;
}
deque_entry;
/** Private structure.
*/
struct mlt_deque_s
{
deque_entry *list;
int size;
int count;
};
/** Create a deque.
*/
mlt_deque mlt_deque_init( )
{
mlt_deque this = malloc( sizeof( struct mlt_deque_s ) );
if ( this != NULL )
{
this->list = NULL;
this->size = 0;
this->count = 0;
}
return this;
}
/** Return the number of items in the deque.
*/
int mlt_deque_count( mlt_deque this )
{
return this->count;
}
/** Allocate space on the deque.
*/
static int mlt_deque_allocate( mlt_deque this )
{
if ( this->count == this->size )
{
this->list = realloc( this->list, sizeof( deque_entry ) * ( this->size + 20 ) );
this->size += 20;
}
return this->list == NULL;
}
/** Push an item to the end.
*/
int mlt_deque_push_back( mlt_deque this, void *item )
{
int error = mlt_deque_allocate( this );
if ( error == 0 )
this->list[ this->count ++ ].addr = item;
return error;
}
/** Pop an item.
*/
void *mlt_deque_pop_back( mlt_deque this )
{
return this->count > 0 ? this->list[ -- this->count ].addr : NULL;
}
/** Queue an item at the start.
*/
int mlt_deque_push_front( mlt_deque this, void *item )
{
int error = mlt_deque_allocate( this );
if ( error == 0 )
{
memmove( &this->list[ 1 ], this->list, ( this->count ++ ) * sizeof( deque_entry ) );
this->list[ 0 ].addr = item;
}
return error;
}
/** Remove an item from the start.
*/
void *mlt_deque_pop_front( mlt_deque this )
{
void *item = NULL;
if ( this->count > 0 )
{
item = this->list[ 0 ].addr;
memmove( this->list, &this->list[ 1 ], ( -- this->count ) * sizeof( deque_entry ) );
}
return item;
}
/** Inquire on item at back of deque but don't remove.
*/
void *mlt_deque_peek_back( mlt_deque this )
{
return this->count > 0 ? this->list[ this->count - 1 ].addr : NULL;
}
/** Inquire on item at front of deque but don't remove.
*/
void *mlt_deque_peek_front( mlt_deque this )
{
return this->count > 0 ? this->list[ 0 ].addr : NULL;
}
/** Push an item to the end.
*/
int mlt_deque_push_back_int( mlt_deque this, int item )
{
int error = mlt_deque_allocate( this );
if ( error == 0 )
this->list[ this->count ++ ].value = item;
return error;
}
/** Pop an item.
*/
int mlt_deque_pop_back_int( mlt_deque this )
{
return this->count > 0 ? this->list[ -- this->count ].value : 0;
}
/** Queue an item at the start.
*/
int mlt_deque_push_front_int( mlt_deque this, int item )
{
int error = mlt_deque_allocate( this );
if ( error == 0 )
{
memmove( &this->list[ 1 ], this->list, ( this->count ++ ) * sizeof( deque_entry ) );
this->list[ 0 ].value = item;
}
return error;
}
/** Remove an item from the start.
*/
int mlt_deque_pop_front_int( mlt_deque this )
{
int item = 0;
if ( this->count > 0 )
{
item = this->list[ 0 ].value;
memmove( this->list, &this->list[ 1 ], ( -- this->count ) * sizeof( deque_entry ) );
}
return item;
}
/** Inquire on item at back of deque but don't remove.
*/
int mlt_deque_peek_back_int( mlt_deque this )
{
return this->count > 0 ? this->list[ this->count - 1 ].value : 0;
}
/** Inquire on item at front of deque but don't remove.
*/
int mlt_deque_peek_front_int( mlt_deque this )
{
return this->count > 0 ? this->list[ 0 ].value : 0;
}
/** Push an item to the end.
*/
int mlt_deque_push_back_double( mlt_deque this, double item )
{
int error = mlt_deque_allocate( this );
if ( error == 0 )
this->list[ this->count ++ ].floating = item;
return error;
}
/** Pop an item.
*/
double mlt_deque_pop_back_double( mlt_deque this )
{
return this->count > 0 ? this->list[ -- this->count ].floating : 0;
}
/** Queue an item at the start.
*/
int mlt_deque_push_front_double( mlt_deque this, double item )
{
int error = mlt_deque_allocate( this );
if ( error == 0 )
{
memmove( &this->list[ 1 ], this->list, ( this->count ++ ) * sizeof( deque_entry ) );
this->list[ 0 ].floating = item;
}
return error;
}
/** Remove an item from the start.
*/
double mlt_deque_pop_front_double( mlt_deque this )
{
double item = 0;
if ( this->count > 0 )
{
item = this->list[ 0 ].floating;
memmove( this->list, &this->list[ 1 ], ( -- this->count ) * sizeof( deque_entry ) );
}
return item;
}
/** Inquire on item at back of deque but don't remove.
*/
double mlt_deque_peek_back_double( mlt_deque this )
{
return this->count > 0 ? this->list[ this->count - 1 ].floating : 0;
}
/** Inquire on item at front of deque but don't remove.
*/
double mlt_deque_peek_front_double( mlt_deque this )
{
return this->count > 0 ? this->list[ 0 ].floating : 0;
}
/** Close the queue.
*/
void mlt_deque_close( mlt_deque this )
{
free( this->list );
free( this );
}

@ -0,0 +1,51 @@
/*
* mlt_deque.h -- double ended queue
* Copyright (C) 2003-2004 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MLT_DEQUE_H_
#define _MLT_DEQUE_H_
#include "mlt_types.h"
extern mlt_deque mlt_deque_init( );
extern int mlt_deque_count( mlt_deque self );
extern int mlt_deque_push_back( mlt_deque self, void *item );
extern void *mlt_deque_pop_back( mlt_deque self );
extern int mlt_deque_push_front( mlt_deque self, void *item );
extern void *mlt_deque_pop_front( mlt_deque self );
extern void *mlt_deque_peek_back( mlt_deque self );
extern void *mlt_deque_peek_front( mlt_deque self );
extern int mlt_deque_push_back_int( mlt_deque self, int item );
extern int mlt_deque_pop_back_int( mlt_deque self );
extern int mlt_deque_push_front_int( mlt_deque self, int item );
extern int mlt_deque_pop_front_int( mlt_deque self );
extern int mlt_deque_peek_back_int( mlt_deque self );
extern int mlt_deque_peek_front_int( mlt_deque self );
extern int mlt_deque_push_back_double( mlt_deque self, double item );
extern double mlt_deque_pop_back_double( mlt_deque self );
extern int mlt_deque_push_front_double( mlt_deque self, double item );
extern double mlt_deque_pop_front_double( mlt_deque self );
extern double mlt_deque_peek_back_double( mlt_deque self );
extern double mlt_deque_peek_front_double( mlt_deque self );
extern void mlt_deque_close( mlt_deque self );
#endif

@ -0,0 +1,403 @@
/*
* mlt_events.h -- event handling
* Copyright (C) 2004-2005 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <pthread.h>
#include "mlt_properties.h"
#include "mlt_events.h"
/** Memory leak checks.
*/
//#define _MLT_EVENT_CHECKS_
#ifdef _MLT_EVENT_CHECKS_
static int events_created = 0;
static int events_destroyed = 0;
#endif
struct mlt_events_struct
{
mlt_properties owner;
mlt_properties list;
};
typedef struct mlt_events_struct *mlt_events;
struct mlt_event_struct
{
mlt_events owner;
int ref_count;
int block_count;
mlt_listener listener;
void *service;
};
/** Increment the reference count on this event.
*/
void mlt_event_inc_ref( mlt_event this )
{
if ( this != NULL )
this->ref_count ++;
}
/** Increment the block count on this event.
*/
void mlt_event_block( mlt_event this )
{
if ( this != NULL && this->owner != NULL )
this->block_count ++;
}
/** Decrement the block count on this event.
*/
void mlt_event_unblock( mlt_event this )
{
if ( this != NULL && this->owner != NULL )
this->block_count --;
}
/** Close this event.
*/
void mlt_event_close( mlt_event this )
{
if ( this != NULL )
{
if ( -- this->ref_count == 1 )
this->owner = NULL;
if ( this->ref_count <= 0 )
{
#ifdef _MLT_EVENT_CHECKS_
events_destroyed ++;
fprintf( stderr, "Events created %d, destroyed %d\n", events_created, events_destroyed );
#endif
free( this );
}
}
}
/** Forward declaration to private functions.
*/
static mlt_events mlt_events_fetch( mlt_properties );
static void mlt_events_store( mlt_properties, mlt_events );
static void mlt_events_close( mlt_events );
/** Initialise the events structure.
*/
void mlt_events_init( mlt_properties this )
{
mlt_events events = mlt_events_fetch( this );
if ( events == NULL )
{
events = malloc( sizeof( struct mlt_events_struct ) );
events->list = mlt_properties_new( );
mlt_events_store( this, events );
}
}
/** Register an event and transmitter.
*/
int mlt_events_register( mlt_properties this, char *id, mlt_transmitter transmitter )
{
int error = 1;
mlt_events events = mlt_events_fetch( this );
if ( events != NULL )
{
mlt_properties list = events->list;
char temp[ 128 ];
error = mlt_properties_set_data( list, id, transmitter, 0, NULL, NULL );
sprintf( temp, "list:%s", id );
if ( mlt_properties_get_data( list, temp, NULL ) == NULL )
mlt_properties_set_data( list, temp, mlt_properties_new( ), 0, ( mlt_destructor )mlt_properties_close, NULL );
}
return error;
}
/** Fire an event.
*/
void mlt_events_fire( mlt_properties this, char *id, ... )
{
mlt_events events = mlt_events_fetch( this );
if ( events != NULL )
{
int i = 0;
va_list alist;
void *args[ 10 ];
mlt_properties list = events->list;
mlt_properties listeners = NULL;
char temp[ 128 ];
mlt_transmitter transmitter = mlt_properties_get_data( list, id, NULL );
sprintf( temp, "list:%s", id );
listeners = mlt_properties_get_data( list, temp, NULL );
va_start( alist, id );
do
args[ i ] = va_arg( alist, void * );
while( args[ i ++ ] != NULL );
va_end( alist );
if ( listeners != NULL )
{
for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
{
mlt_event event = mlt_properties_get_data_at( listeners, i, NULL );
if ( event != NULL && event->owner != NULL && event->block_count == 0 )
{
if ( transmitter != NULL )
transmitter( event->listener, event->owner, event->service, args );
else
event->listener( event->owner, event->service );
}
}
}
}
}
/** Register a listener.
*/
mlt_event mlt_events_listen( mlt_properties this, void *service, char *id, mlt_listener listener )
{
mlt_event event = NULL;
mlt_events events = mlt_events_fetch( this );
if ( events != NULL )
{
mlt_properties list = events->list;
mlt_properties listeners = NULL;
char temp[ 128 ];
sprintf( temp, "list:%s", id );
listeners = mlt_properties_get_data( list, temp, NULL );
if ( listeners != NULL )
{
int first_null = -1;
int i = 0;
for ( i = 0; event == NULL && i < mlt_properties_count( listeners ); i ++ )
{
mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
if ( entry != NULL && entry->owner != NULL )
{
if ( entry->service == service && entry->listener == listener )
event = entry;
}
else if ( ( entry == NULL || entry->owner == NULL ) && first_null == -1 )
{
first_null = i;
}
}
if ( event == NULL )
{
event = malloc( sizeof( struct mlt_event_struct ) );
if ( event != NULL )
{
#ifdef _MLT_EVENT_CHECKS_
events_created ++;
#endif
sprintf( temp, "%d", first_null == -1 ? mlt_properties_count( listeners ) : first_null );
event->owner = events;
event->ref_count = 0;
event->block_count = 0;
event->listener = listener;
event->service = service;
mlt_properties_set_data( listeners, temp, event, 0, ( mlt_destructor )mlt_event_close, NULL );
mlt_event_inc_ref( event );
}
}
}
}
return event;
}
/** Block all events for a given service.
*/
void mlt_events_block( mlt_properties this, void *service )
{
mlt_events events = mlt_events_fetch( this );
if ( events != NULL )
{
int i = 0, j = 0;
mlt_properties list = events->list;
for ( j = 0; j < mlt_properties_count( list ); j ++ )
{
char *temp = mlt_properties_get_name( list, j );
if ( !strncmp( temp, "list:", 5 ) )
{
mlt_properties listeners = mlt_properties_get_data( list, temp, NULL );
for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
{
mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
if ( entry != NULL && entry->service == service )
mlt_event_block( entry );
}
}
}
}
}
/** Unblock all events for a given service.
*/
void mlt_events_unblock( mlt_properties this, void *service )
{
mlt_events events = mlt_events_fetch( this );
if ( events != NULL )
{
int i = 0, j = 0;
mlt_properties list = events->list;
for ( j = 0; j < mlt_properties_count( list ); j ++ )
{
char *temp = mlt_properties_get_name( list, j );
if ( !strncmp( temp, "list:", 5 ) )
{
mlt_properties listeners = mlt_properties_get_data( list, temp, NULL );
for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
{
mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
if ( entry != NULL && entry->service == service )
mlt_event_unblock( entry );
}
}
}
}
}
/** Disconnect all events for a given service.
*/
void mlt_events_disconnect( mlt_properties this, void *service )
{
mlt_events events = mlt_events_fetch( this );
if ( events != NULL )
{
int i = 0, j = 0;
mlt_properties list = events->list;
for ( j = 0; j < mlt_properties_count( list ); j ++ )
{
char *temp = mlt_properties_get_name( list, j );
if ( !strncmp( temp, "list:", 5 ) )
{
mlt_properties listeners = mlt_properties_get_data( list, temp, NULL );
for ( i = 0; i < mlt_properties_count( listeners ); i ++ )
{
mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL );
char *name = mlt_properties_get_name( listeners, i );
if ( entry != NULL && entry->service == service )
mlt_properties_set_data( listeners, name, NULL, 0, NULL, NULL );
}
}
}
}
}
typedef struct
{
int done;
pthread_cond_t cond;
pthread_mutex_t mutex;
}
condition_pair;
static void mlt_events_listen_for( mlt_properties this, condition_pair *pair )
{
pthread_mutex_lock( &pair->mutex );
if ( pair->done == 0 )
{
pthread_cond_signal( &pair->cond );
pthread_mutex_unlock( &pair->mutex );
}
}
mlt_event mlt_events_setup_wait_for( mlt_properties this, char *id )
{
condition_pair *pair = malloc( sizeof( condition_pair ) );
pair->done = 0;
pthread_cond_init( &pair->cond, NULL );
pthread_mutex_init( &pair->mutex, NULL );
pthread_mutex_lock( &pair->mutex );
return mlt_events_listen( this, pair, id, ( mlt_listener )mlt_events_listen_for );
}
void mlt_events_wait_for( mlt_properties this, mlt_event event )
{
if ( event != NULL )
{
condition_pair *pair = event->service;
pthread_cond_wait( &pair->cond, &pair->mutex );
}
}
void mlt_events_close_wait_for( mlt_properties this, mlt_event event )
{
if ( event != NULL )
{
condition_pair *pair = event->service;
event->owner = NULL;
pair->done = 0;
pthread_mutex_unlock( &pair->mutex );
pthread_mutex_destroy( &pair->mutex );
pthread_cond_destroy( &pair->cond );
}
}
/** Fetch the events object.
*/
static mlt_events mlt_events_fetch( mlt_properties this )
{
mlt_events events = NULL;
if ( this != NULL )
events = mlt_properties_get_data( this, "_events", NULL );
return events;
}
/** Store the events object.
*/
static void mlt_events_store( mlt_properties this, mlt_events events )
{
if ( this != NULL && events != NULL )
mlt_properties_set_data( this, "_events", events, 0, ( mlt_destructor )mlt_events_close, NULL );
}
/** Close the events object.
*/
static void mlt_events_close( mlt_events events )
{
if ( events != NULL )
{
mlt_properties_close( events->list );
free( events );
}
}

@ -0,0 +1,52 @@
/*
* mlt_events.h -- event handling
* Copyright (C) 2004-2005 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MLT_EVENTS_H_
#define _MLT_EVENTS_H_
#include "mlt_types.h"
#if GCC_VERSION >= 40000
typedef void ( *mlt_transmitter )( void *, ... );
typedef void ( *mlt_listener )( void *, ... );
#else
typedef void ( *mlt_transmitter )( );
typedef void ( *mlt_listener )( );
#endif
extern void mlt_events_init( mlt_properties self );
extern int mlt_events_register( mlt_properties self, char *id, mlt_transmitter transmitter );
extern void mlt_events_fire( mlt_properties self, char *id, ... );
extern mlt_event mlt_events_listen( mlt_properties self, void *service, char *id, mlt_listener listener );
extern void mlt_events_block( mlt_properties self, void *service );
extern void mlt_events_unblock( mlt_properties self, void *service );
extern void mlt_events_disconnect( mlt_properties self, void *service );
extern mlt_event mlt_events_setup_wait_for( mlt_properties self, char *id );
extern void mlt_events_wait_for( mlt_properties self, mlt_event event );
extern void mlt_events_close_wait_for( mlt_properties self, mlt_event event );
extern void mlt_event_inc_ref( mlt_event self );
extern void mlt_event_block( mlt_event self );
extern void mlt_event_unblock( mlt_event self );
extern void mlt_event_close( mlt_event self );
#endif

@ -0,0 +1,304 @@
/*
* mlt_factory.c -- the factory method interfaces
* Copyright (C) 2003-2004 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "mlt.h"
#include "mlt_repository.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/** Singleton repositories
*/
static char *mlt_prefix = NULL;
static mlt_properties global_properties = NULL;
static mlt_properties object_list = NULL;
static mlt_repository producers = NULL;
static mlt_repository filters = NULL;
static mlt_repository transitions = NULL;
static mlt_repository consumers = NULL;
static mlt_properties event_object = NULL;
static int unique_id = 0;
/** Event transmitters.
*/
static void mlt_factory_create_request( mlt_listener listener, mlt_properties owner, mlt_service this, void **args )
{
if ( listener != NULL )
listener( owner, this, ( char * )args[ 0 ], ( char * )args[ 1 ], ( mlt_service * )args[ 2 ] );
}
static void mlt_factory_create_done( mlt_listener listener, mlt_properties owner, mlt_service this, void **args )
{
if ( listener != NULL )
listener( owner, this, ( char * )args[ 0 ], ( char * )args[ 1 ], ( mlt_service )args[ 2 ] );
}
/** Construct the factories.
*/
int mlt_factory_init( const char *prefix )
{
// Only initialise once
if ( mlt_prefix == NULL )
{
// Allow user over rides
if ( prefix == NULL || !strcmp( prefix, "" ) )
prefix = getenv( "MLT_REPOSITORY" );
// If no directory is specified, default to install directory
if ( prefix == NULL )
prefix = PREFIX_DATA;
// Store the prefix for later retrieval
mlt_prefix = strdup( prefix );
// Initialise the pool
mlt_pool_init( );
// Create and set up the events object
event_object = mlt_properties_new( );
mlt_events_init( event_object );
mlt_events_register( event_object, "producer-create-request", ( mlt_transmitter )mlt_factory_create_request );
mlt_events_register( event_object, "producer-create-done", ( mlt_transmitter )mlt_factory_create_done );
mlt_events_register( event_object, "filter-create-request", ( mlt_transmitter )mlt_factory_create_request );
mlt_events_register( event_object, "filter-create-done", ( mlt_transmitter )mlt_factory_create_done );
mlt_events_register( event_object, "transition-create-request", ( mlt_transmitter )mlt_factory_create_request );
mlt_events_register( event_object, "transition-create-done", ( mlt_transmitter )mlt_factory_create_done );
mlt_events_register( event_object, "consumer-create-request", ( mlt_transmitter )mlt_factory_create_request );
mlt_events_register( event_object, "consumer-create-done", ( mlt_transmitter )mlt_factory_create_done );
// Create the global properties
global_properties = mlt_properties_new( );
// Create the object list.
object_list = mlt_properties_new( );
// Create a repository for each service type
producers = mlt_repository_init( object_list, prefix, "producers", "mlt_create_producer" );
filters = mlt_repository_init( object_list, prefix, "filters", "mlt_create_filter" );
transitions = mlt_repository_init( object_list, prefix, "transitions", "mlt_create_transition" );
consumers = mlt_repository_init( object_list, prefix, "consumers", "mlt_create_consumer" );
// Force a clean up when app closes
atexit( mlt_factory_close );
}
// Allow property refresh on a subsequent initialisation
if ( global_properties != NULL )
{
mlt_properties_set_or_default( global_properties, "MLT_NORMALISATION", getenv( "MLT_NORMALISATION" ), "PAL" );
mlt_properties_set_or_default( global_properties, "MLT_PRODUCER", getenv( "MLT_PRODUCER" ), "fezzik" );
mlt_properties_set_or_default( global_properties, "MLT_CONSUMER", getenv( "MLT_CONSUMER" ), "sdl" );
mlt_properties_set( global_properties, "MLT_TEST_CARD", getenv( "MLT_TEST_CARD" ) );
mlt_properties_set_or_default( global_properties, "MLT_PROFILE", getenv( "MLT_PROFILE" ), "dv_pal" );
// Load the most appropriate profile
// MLT_PROFILE preferred
if ( getenv( "MLT_PROFILE" ) )
mlt_profile_select( mlt_environment( "MLT_PROFILE" ) );
// MLT_NORMALISATION backwards compatibility
else if ( strcmp( mlt_environment( "MLT_NORMALISATION" ), "PAL" ) )
mlt_profile_select( "dv_ntsc" );
else
mlt_profile_select( "dv_pal" );
}
return 0;
}
/** Fetch the events object.
*/
mlt_properties mlt_factory_event_object( )
{
return event_object;
}
/** Fetch the prefix used in this instance.
*/
const char *mlt_factory_prefix( )
{
return mlt_prefix;
}
/** Get a value from the environment.
*/
char *mlt_environment( const char *name )
{
return mlt_properties_get( global_properties, name );
}
/** Set a value in the environment.
*/
int mlt_environment_set( const char *name, const char *value )
{
return mlt_properties_set( global_properties, name, value );
}
/** Fetch a producer from the repository.
*/
mlt_producer mlt_factory_producer( const char *service, void *input )
{
mlt_producer obj = NULL;
// Pick up the default normalising producer if necessary
if ( service == NULL )
service = mlt_environment( "MLT_PRODUCER" );
// Offer the application the chance to 'create'
mlt_events_fire( event_object, "producer-create-request", service, input, &obj, NULL );
// Try to instantiate via the specified service
if ( obj == NULL )
{
obj = mlt_repository_fetch( producers, service, input );
mlt_events_fire( event_object, "producer-create-done", service, input, obj, NULL );
if ( obj != NULL )
{
mlt_properties properties = MLT_PRODUCER_PROPERTIES( obj );
mlt_properties_set_int( properties, "_unique_id", ++ unique_id );
mlt_properties_set( properties, "mlt_type", "producer" );
if ( mlt_properties_get_int( properties, "_mlt_service_hidden" ) == 0 )
mlt_properties_set( properties, "mlt_service", service );
}
}
return obj;
}
/** Fetch a filter from the repository.
*/
mlt_filter mlt_factory_filter( const char *service, void *input )
{
mlt_filter obj = NULL;
// Offer the application the chance to 'create'
mlt_events_fire( event_object, "filter-create-request", service, input, &obj, NULL );
if ( obj == NULL )
{
obj = mlt_repository_fetch( filters, service, input );
mlt_events_fire( event_object, "filter-create-done", service, input, obj, NULL );
}
if ( obj != NULL )
{
mlt_properties properties = MLT_FILTER_PROPERTIES( obj );
mlt_properties_set_int( properties, "_unique_id", ++ unique_id );
mlt_properties_set( properties, "mlt_type", "filter" );
mlt_properties_set( properties, "mlt_service", service );
}
return obj;
}
/** Fetch a transition from the repository.
*/
mlt_transition mlt_factory_transition( const char *service, void *input )
{
mlt_transition obj = NULL;
// Offer the application the chance to 'create'
mlt_events_fire( event_object, "transition-create-request", service, input, &obj, NULL );
if ( obj == NULL )
{
obj = mlt_repository_fetch( transitions, service, input );
mlt_events_fire( event_object, "transition-create-done", service, input, obj, NULL );
}
if ( obj != NULL )
{
mlt_properties properties = MLT_TRANSITION_PROPERTIES( obj );
mlt_properties_set_int( properties, "_unique_id", ++ unique_id );
mlt_properties_set( properties, "mlt_type", "transition" );
mlt_properties_set( properties, "mlt_service", service );
}
return obj;
}
/** Fetch a consumer from the repository
*/
mlt_consumer mlt_factory_consumer( const char *service, void *input )
{
mlt_consumer obj = NULL;
if ( service == NULL )
service = mlt_environment( "MLT_CONSUMER" );
// Offer the application the chance to 'create'
mlt_events_fire( event_object, "consumer-create-request", service, input, &obj, NULL );
if ( obj == NULL )
{
obj = mlt_repository_fetch( consumers, service, input );
mlt_events_fire( event_object, "consumer-create-done", service, input, obj, NULL );
}
if ( obj != NULL )
{
mlt_properties properties = MLT_CONSUMER_PROPERTIES( obj );
mlt_properties_set_int( properties, "_unique_id", ++ unique_id );
mlt_properties_set( properties, "mlt_type", "consumer" );
mlt_properties_set( properties, "mlt_service", service );
}
return obj;
}
/** Register an object for clean up.
*/
void mlt_factory_register_for_clean_up( void *ptr, mlt_destructor destructor )
{
char unique[ 256 ];
sprintf( unique, "%08d", mlt_properties_count( global_properties ) );
mlt_properties_set_data( global_properties, unique, ptr, 0, destructor, NULL );
}
/** Close the factory.
*/
void mlt_factory_close( )
{
if ( mlt_prefix != NULL )
{
mlt_properties_close( event_object );
mlt_repository_close( producers );
mlt_repository_close( filters );
mlt_repository_close( transitions );
mlt_repository_close( consumers );
mlt_properties_close( global_properties );
mlt_properties_close( object_list );
free( mlt_prefix );
mlt_prefix = NULL;
mlt_pool_close( );
mlt_profile_close();
}
}

@ -0,0 +1,38 @@
/*
* mlt_factory.h -- the factory method interfaces
* Copyright (C) 2003-2004 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MLT_FACTORY_H
#define _MLT_FACTORY_H
#include "mlt_types.h"
extern int mlt_factory_init( const char *prefix );
extern const char *mlt_factory_prefix( );
extern char *mlt_environment( const char *name );
extern int mlt_environment_set( const char *name, const char *value );
extern mlt_properties mlt_factory_event_object( );
extern mlt_producer mlt_factory_producer( const char *name, void *input );
extern mlt_filter mlt_factory_filter( const char *name, void *input );
extern mlt_transition mlt_factory_transition( const char *name, void *input );
extern mlt_consumer mlt_factory_consumer( const char *name, void *input );
extern void mlt_factory_register_for_clean_up( void *ptr, mlt_destructor destructor );
extern void mlt_factory_close( );
#endif

@ -0,0 +1,193 @@
/*
* mlt_field.c -- A field for planting multiple transitions and filters
* Copyright (C) 2003-2004 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mlt_field.h"
#include "mlt_service.h"
#include "mlt_filter.h"
#include "mlt_transition.h"
#include "mlt_multitrack.h"
#include "mlt_tractor.h"
#include <stdlib.h>
#include <string.h>
/** Private structures.
*/
struct mlt_field_s
{
// This is the producer we're connected to
mlt_service producer;
// Multitrack
mlt_multitrack multitrack;
// Tractor
mlt_tractor tractor;
};
/** Constructor.
We construct a multitrack and a tractor here.
*/
mlt_field mlt_field_init( )
{
// Initialise the field
mlt_field this = calloc( sizeof( struct mlt_field_s ), 1 );
// Initialise it
if ( this != NULL )
{
// Construct a multitrack
this->multitrack = mlt_multitrack_init( );
// Construct a tractor
this->tractor = mlt_tractor_init( );
// The first plant will be connected to the mulitrack
this->producer = MLT_MULTITRACK_SERVICE( this->multitrack );
// Connect the tractor to the multitrack
mlt_tractor_connect( this->tractor, this->producer );
}
// Return this
return this;
}
mlt_field mlt_field_new( mlt_multitrack multitrack, mlt_tractor tractor )
{
// Initialise the field
mlt_field this = calloc( sizeof( struct mlt_field_s ), 1 );
// Initialise it
if ( this != NULL )
{
// Construct a multitrack
this->multitrack = multitrack;
// Construct a tractor
this->tractor = tractor;
// The first plant will be connected to the mulitrack
this->producer = MLT_MULTITRACK_SERVICE( this->multitrack );
// Connect the tractor to the multitrack
mlt_tractor_connect( this->tractor, this->producer );
}
// Return this
return this;
}
/** Get the service associated to this field.
*/
mlt_service mlt_field_service( mlt_field this )
{
return MLT_TRACTOR_SERVICE( this->tractor );
}
/** Get the multi track.
*/
mlt_multitrack mlt_field_multitrack( mlt_field this )
{
return this != NULL ? this->multitrack : NULL;
}
/** Get the tractor.
*/
mlt_tractor mlt_field_tractor( mlt_field this )
{
return this != NULL ? this->tractor : NULL;
}
/** Get the properties associated to this field.
*/
mlt_properties mlt_field_properties( mlt_field this )
{
return MLT_SERVICE_PROPERTIES( mlt_field_service( this ) );
}
/** Plant a filter.
*/
int mlt_field_plant_filter( mlt_field this, mlt_filter that, int track )
{
// Connect the filter to the last producer
int result = mlt_filter_connect( that, this->producer, track );
// If sucessful, then we'll use this for connecting in the future
if ( result == 0 )
{
// This is now the new producer
this->producer = MLT_FILTER_SERVICE( that );
// Reconnect tractor to new producer
mlt_tractor_connect( this->tractor, this->producer );
// Fire an event
mlt_events_fire( mlt_field_properties( this ), "service-changed", NULL );
}
return result;
}
/** Plant a transition.
*/
int mlt_field_plant_transition( mlt_field this, mlt_transition that, int a_track, int b_track )
{
// Connect the transition to the last producer
int result = mlt_transition_connect( that, this->producer, a_track, b_track );
// If sucessful, then we'll use this for connecting in the future
if ( result == 0 )
{
// This is now the new producer
this->producer = MLT_TRANSITION_SERVICE( that );
// Reconnect tractor to new producer
mlt_tractor_connect( this->tractor, this->producer );
// Fire an event
mlt_events_fire( mlt_field_properties( this ), "service-changed", NULL );
}
return 0;
}
/** Close the field.
*/
void mlt_field_close( mlt_field this )
{
if ( this != NULL && mlt_properties_dec_ref( mlt_field_properties( this ) ) <= 0 )
{
//mlt_tractor_close( this->tractor );
//mlt_multitrack_close( this->multitrack );
free( this );
}
}

@ -0,0 +1,37 @@
/*
* mlt_field.h -- A field for planting multiple transitions and services
* Copyright (C) 2003-2004 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MLT_FIELD_H_
#define _MLT_FIELD_H_
#include "mlt_types.h"
extern mlt_field mlt_field_init( );
extern mlt_field mlt_field_new( mlt_multitrack multitrack, mlt_tractor tractor );
extern mlt_service mlt_field_service( mlt_field self );
extern mlt_tractor mlt_field_tractor( mlt_field self );
extern mlt_multitrack mlt_field_multitrack( mlt_field self );
extern mlt_properties mlt_field_properties( mlt_field self );
extern int mlt_field_plant_filter( mlt_field self, mlt_filter that, int track );
extern int mlt_field_plant_transition( mlt_field self, mlt_transition that, int a_track, int b_track );
extern void mlt_field_close( mlt_field self );
#endif

@ -0,0 +1,213 @@
/*
* mlt_filter.c -- abstraction for all filter services
* Copyright (C) 2003-2004 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "mlt_filter.h"
#include "mlt_frame.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int filter_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
/** Constructor method.
*/
int mlt_filter_init( mlt_filter this, void *child )
{
mlt_service service = &this->parent;
memset( this, 0, sizeof( struct mlt_filter_s ) );
this->child = child;
if ( mlt_service_init( service, this ) == 0 )
{
mlt_properties properties = MLT_SERVICE_PROPERTIES( service );
// Override the get_frame method
service->get_frame = filter_get_frame;
// Define the destructor
service->close = ( mlt_destructor )mlt_filter_close;
service->close_object = this;
// Default in, out, track properties
mlt_properties_set_position( properties, "in", 0 );
mlt_properties_set_position( properties, "out", 0 );
mlt_properties_set_int( properties, "track", 0 );
return 0;
}
return 1;
}
/** Create a new filter.
*/
mlt_filter mlt_filter_new( )
{
mlt_filter this = calloc( 1, sizeof( struct mlt_filter_s ) );
if ( this != NULL )
mlt_filter_init( this, NULL );
return this;
}
/** Get the service associated to this filter
*/
mlt_service mlt_filter_service( mlt_filter this )
{
return this != NULL ? &this->parent : NULL;
}
/** Get the properties associated to this filter.
*/
mlt_properties mlt_filter_properties( mlt_filter this )
{
return MLT_SERVICE_PROPERTIES( MLT_FILTER_SERVICE( this ) );
}
/** Connect this filter to a producers track. Note that a filter only operates
on a single track, and by default it operates on the entirety of that track.
*/
int mlt_filter_connect( mlt_filter this, mlt_service producer, int index )
{
int ret = mlt_service_connect_producer( &this->parent, producer, index );
// If the connection was successful, grab the producer, track and reset in/out
if ( ret == 0 )
{
mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent );
mlt_properties_set_position( properties, "in", 0 );
mlt_properties_set_position( properties, "out", 0 );
mlt_properties_set_int( properties, "track", index );
}
return ret;
}
/** Tune the in/out points.
*/
void mlt_filter_set_in_and_out( mlt_filter this, mlt_position in, mlt_position out )
{
mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent );
mlt_properties_set_position( properties, "in", in );
mlt_properties_set_position( properties, "out", out );
}
/** Return the track that this filter is operating on.
*/
int mlt_filter_get_track( mlt_filter this )
{
mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent );
return mlt_properties_get_int( properties, "track" );
}
/** Get the in point.
*/
mlt_position mlt_filter_get_in( mlt_filter this )
{
mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent );
return mlt_properties_get_position( properties, "in" );
}
/** Get the out point.
*/
mlt_position mlt_filter_get_out( mlt_filter this )
{
mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent );
return mlt_properties_get_position( properties, "out" );
}
/** Process the frame.
*/
mlt_frame mlt_filter_process( mlt_filter this, mlt_frame frame )
{
int disable = mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "disable" );
if ( disable || this->process == NULL )
return frame;
else
return this->process( this, frame );
}
/** Get a frame from this filter.
*/
static int filter_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
{
mlt_filter this = service->child;
// Get coords in/out/track
int track = mlt_filter_get_track( this );
int in = mlt_filter_get_in( this );
int out = mlt_filter_get_out( this );
// Get the producer this is connected to
mlt_service producer = mlt_service_producer( &this->parent );
// If the frame request is for this filters track, we need to process it
if ( index == track || track == -1 )
{
int ret = mlt_service_get_frame( producer, frame, index );
if ( ret == 0 )
{
mlt_position position = mlt_frame_get_position( *frame );
if ( position >= in && ( out == 0 || position <= out ) )
*frame = mlt_filter_process( this, *frame );
return 0;
}
else
{
*frame = mlt_frame_init( );
return 0;
}
}
else
{
return mlt_service_get_frame( producer, frame, index );
}
}
/** Close the filter.
*/
void mlt_filter_close( mlt_filter this )
{
if ( this != NULL && mlt_properties_dec_ref( MLT_FILTER_PROPERTIES( this ) ) <= 0 )
{
if ( this->close != NULL )
{
this->close( this );
}
else
{
this->parent.close = NULL;
mlt_service_close( &this->parent );
}
free( this );
}
}

@ -0,0 +1,62 @@
/*
* mlt_filter.h -- abstraction for all filter services
* Copyright (C) 2003-2004 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MLT_FILTER_H_
#define _MLT_FILTER_H_
#include "mlt_service.h"
/** The interface definition for all filters.
*/
struct mlt_filter_s
{
/* We're implementing service here */
struct mlt_service_s parent;
/* public virtual */
void ( *close )( mlt_filter );
/* protected filter method */
mlt_frame ( *process )( mlt_filter, mlt_frame );
/* Protected */
void *child;
};
/** Public final methods
*/
#define MLT_FILTER_SERVICE( filter ) ( &( filter )->parent )
#define MLT_FILTER_PROPERTIES( filter ) MLT_SERVICE_PROPERTIES( MLT_FILTER_SERVICE( filter ) )
extern int mlt_filter_init( mlt_filter self, void *child );
extern mlt_filter mlt_filter_new( );
extern mlt_service mlt_filter_service( mlt_filter self );
extern mlt_properties mlt_filter_properties( mlt_filter self );
extern mlt_frame mlt_filter_process( mlt_filter self, mlt_frame that );
extern int mlt_filter_connect( mlt_filter self, mlt_service producer, int index );
extern void mlt_filter_set_in_and_out( mlt_filter self, mlt_position in, mlt_position out );
extern int mlt_filter_get_track( mlt_filter self );
extern mlt_position mlt_filter_get_in( mlt_filter self );
extern mlt_position mlt_filter_get_out( mlt_filter self );
extern void mlt_filter_close( mlt_filter );
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,118 @@
/*
* mlt_frame.h -- interface for all frame classes
* Copyright (C) 2003-2004 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MLT_FRAME_H_
#define _MLT_FRAME_H_
#include "mlt_properties.h"
#include "mlt_deque.h"
typedef int ( *mlt_get_image )( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable );
typedef int ( *mlt_get_audio )( mlt_frame self, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
struct mlt_frame_s
{
/* We're extending properties here */
struct mlt_properties_s parent;
/* Virtual methods */
uint8_t * ( *get_alpha_mask )( mlt_frame self );
/* Private properties */
mlt_deque stack_image;
mlt_deque stack_audio;
mlt_deque stack_service;
};
#define MLT_FRAME_PROPERTIES( frame ) ( &( frame )->parent )
#define MLT_FRAME_SERVICE_STACK( frame ) ( ( frame )->stack_service )
#define MLT_FRAME_IMAGE_STACK( frame ) ( ( frame )->stack_image )
#define MLT_FRAME_AUDIO_STACK( frame ) ( ( frame )->stack_audio )
extern mlt_frame mlt_frame_init( );
extern mlt_properties mlt_frame_properties( mlt_frame self );
extern int mlt_frame_is_test_card( mlt_frame self );
extern int mlt_frame_is_test_audio( mlt_frame self );
extern double mlt_frame_get_aspect_ratio( mlt_frame self );
extern int mlt_frame_set_aspect_ratio( mlt_frame self, double value );
extern mlt_position mlt_frame_get_position( mlt_frame self );
extern int mlt_frame_set_position( mlt_frame self, mlt_position value );
extern void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height );
extern int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable );
extern uint8_t *mlt_frame_get_alpha_mask( mlt_frame self );
extern int mlt_frame_get_audio( mlt_frame self, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
extern unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h );
extern int mlt_frame_push_get_image( mlt_frame self, mlt_get_image get_image );
extern mlt_get_image mlt_frame_pop_get_image( mlt_frame self );
extern int mlt_frame_push_frame( mlt_frame self, mlt_frame that );
extern mlt_frame mlt_frame_pop_frame( mlt_frame self );
extern int mlt_frame_push_service( mlt_frame self, void *that );
extern void *mlt_frame_pop_service( mlt_frame self );
extern int mlt_frame_push_service_int( mlt_frame self, int that );
extern int mlt_frame_pop_service_int( mlt_frame self );
extern int mlt_frame_push_audio( mlt_frame self, void *that );
extern void *mlt_frame_pop_audio( mlt_frame self );
extern mlt_deque mlt_frame_service_stack( mlt_frame self );
extern mlt_producer mlt_frame_get_original_producer( mlt_frame self );
extern void mlt_frame_close( mlt_frame self );
/* convenience functions */
extern int mlt_convert_yuv422_to_rgb24a( uint8_t *yuv, uint8_t *rgba, unsigned int total );
extern int mlt_convert_rgb24a_to_yuv422( uint8_t *rgba, int width, int height, int stride, uint8_t *yuv, uint8_t *alpha );
extern int mlt_convert_rgb24_to_yuv422( uint8_t *rgb, int width, int height, int stride, uint8_t *yuv );
extern int mlt_convert_bgr24a_to_yuv422( uint8_t *rgba, int width, int height, int stride, uint8_t *yuv, uint8_t *alpha );
extern int mlt_convert_argb_to_yuv422( uint8_t *rgba, int width, int height, int stride, uint8_t *yuv, uint8_t *alpha );
extern int mlt_convert_bgr24_to_yuv422( uint8_t *rgb, int width, int height, int stride, uint8_t *yuv );
extern int mlt_convert_yuv420p_to_yuv422( uint8_t *yuv420p, int width, int height, int stride, uint8_t *yuv );
extern uint8_t *mlt_frame_resize_yuv422( mlt_frame self, int owidth, int oheight );
extern uint8_t *mlt_frame_rescale_yuv422( mlt_frame self, int owidth, int oheight );
extern void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input, int iwidth, int iheight );
extern int mlt_frame_mix_audio( mlt_frame self, mlt_frame that, float weight_start, float weight_end, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
extern int mlt_frame_combine_audio( mlt_frame self, mlt_frame that, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
extern int mlt_sample_calculator( float fps, int frequency, int64_t position );
extern int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position );
/* this macro scales rgb into the yuv gamut, y is scaled by 219/255 and uv by 224/255 */
#define RGB2YUV(r, g, b, y, u, v)\
y = ((263*r + 516*g + 100*b) >> 10) + 16;\
u = ((-152*r - 298*g + 450*b) >> 10) + 128;\
v = ((450*r - 377*g - 73*b) >> 10) + 128;
/* this macro assumes the user has already scaled their rgb down into the broadcast limits */
#define RGB2YUV_UNSCALED(r, g, b, y, u, v)\
y = (299*r + 587*g + 114*b) >> 10;\
u = ((-169*r - 331*g + 500*b) >> 10) + 128;\
v = ((500*r - 419*g - 81*b) >> 10) + 128;\
y = y < 16 ? 16 : y;\
u = u < 16 ? 16 : u;\
v = v < 16 ? 16 : v;\
y = y > 235 ? 235 : y;\
u = u > 240 ? 240 : u;\
v = v > 240 ? 240 : v
#define YUV2RGB( y, u, v, r, g, b ) \
r = ((1192 * ( y - 16 ) + 1634 * ( v - 128 ) ) >> 10 ); \
g = ((1192 * ( y - 16 ) - 832 * ( v - 128 ) - 400 * ( u - 128 ) ) >> 10 ); \
b = ((1192 * ( y - 16 ) + 2066 * ( u - 128 ) ) >> 10 ); \
r = r < 0 ? 0 : r > 255 ? 255 : r; \
g = g < 0 ? 0 : g > 255 ? 255 : g; \
b