Added KDE3 version of MLT
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/libraries/mlt@1095634 283d02a7-25f6-0310-bc7c-ecb5cbfe19dav3.5.13-sru
commit
40f8286642
@ -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).
|
@ -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 |