]> git.sesse.net Git - mlt/commitdiff
Initial revision
authorlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Fri, 19 Dec 2003 13:57:38 +0000 (13:57 +0000)
committerlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Fri, 19 Dec 2003 13:57:38 +0000 (13:57 +0000)
git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@3 d19143bc-622f-0410-bfdd-b5b2a6649095

182 files changed:
ChangeLog [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
configure [new file with mode: 0755]
mlt/ChangeLog [new file with mode: 0644]
mlt/Makefile [new file with mode: 0644]
mlt/README [new file with mode: 0644]
mlt/configure [new file with mode: 0755]
mlt/src/framework/Makefile [new file with mode: 0644]
mlt/src/framework/config.h [new file with mode: 0644]
mlt/src/framework/configure [new file with mode: 0755]
mlt/src/framework/mlt_consumer.c [new file with mode: 0644]
mlt/src/framework/mlt_consumer.h [new file with mode: 0644]
mlt/src/framework/mlt_factory.c [new file with mode: 0644]
mlt/src/framework/mlt_factory.h [new file with mode: 0644]
mlt/src/framework/mlt_filter.c [new file with mode: 0644]
mlt/src/framework/mlt_filter.h [new file with mode: 0644]
mlt/src/framework/mlt_frame.c [new file with mode: 0644]
mlt/src/framework/mlt_frame.h [new file with mode: 0644]
mlt/src/framework/mlt_manager.h [new file with mode: 0644]
mlt/src/framework/mlt_multitrack.c [new file with mode: 0644]
mlt/src/framework/mlt_multitrack.h [new file with mode: 0644]
mlt/src/framework/mlt_playlist.c [new file with mode: 0644]
mlt/src/framework/mlt_playlist.h [new file with mode: 0644]
mlt/src/framework/mlt_producer.c [new file with mode: 0644]
mlt/src/framework/mlt_producer.h [new file with mode: 0644]
mlt/src/framework/mlt_properties.c [new file with mode: 0644]
mlt/src/framework/mlt_properties.h [new file with mode: 0644]
mlt/src/framework/mlt_property.c [new file with mode: 0644]
mlt/src/framework/mlt_property.h [new file with mode: 0644]
mlt/src/framework/mlt_repository.c [new file with mode: 0644]
mlt/src/framework/mlt_repository.h [new file with mode: 0644]
mlt/src/framework/mlt_service.c [new file with mode: 0644]
mlt/src/framework/mlt_service.h [new file with mode: 0644]
mlt/src/framework/mlt_tractor.c [new file with mode: 0644]
mlt/src/framework/mlt_tractor.h [new file with mode: 0644]
mlt/src/framework/mlt_transition.c [new file with mode: 0644]
mlt/src/framework/mlt_transition.h [new file with mode: 0644]
mlt/src/framework/mlt_types.h [new file with mode: 0644]
mlt/src/miracle/configure [new file with mode: 0755]
mlt/src/miracle/miracle.c [new file with mode: 0644]
mlt/src/miracle/miracle_commands.c [new file with mode: 0644]
mlt/src/miracle/miracle_commands.h [new file with mode: 0644]
mlt/src/miracle/miracle_connection.c [new file with mode: 0644]
mlt/src/miracle/miracle_connection.h [new file with mode: 0644]
mlt/src/miracle/miracle_local.c [new file with mode: 0644]
mlt/src/miracle/miracle_local.h [new file with mode: 0644]
mlt/src/miracle/miracle_log.c [new file with mode: 0644]
mlt/src/miracle/miracle_log.h [new file with mode: 0644]
mlt/src/miracle/miracle_server.c [new file with mode: 0644]
mlt/src/miracle/miracle_server.h [new file with mode: 0644]
mlt/src/miracle/miracle_unit.c [new file with mode: 0644]
mlt/src/miracle/miracle_unit.h [new file with mode: 0644]
mlt/src/miracle/miracle_unit_commands.c [new file with mode: 0644]
mlt/src/miracle/miracle_unit_commands.h [new file with mode: 0644]
mlt/src/modules/Makefile [new file with mode: 0644]
mlt/src/modules/configure [new file with mode: 0755]
mlt/src/modules/dv/Makefile [new file with mode: 0644]
mlt/src/modules/dv/configure [new file with mode: 0755]
mlt/src/modules/dv/factory.c [new file with mode: 0644]
mlt/src/modules/dv/producer_libdv.c [new file with mode: 0644]
mlt/src/modules/dv/producer_libdv.h [new file with mode: 0644]
mlt/src/modules/gtk2/Makefile [new file with mode: 0644]
mlt/src/modules/gtk2/configure [new file with mode: 0755]
mlt/src/modules/gtk2/factory.c [new file with mode: 0644]
mlt/src/modules/gtk2/producer_pixbuf.c [new file with mode: 0644]
mlt/src/modules/gtk2/producer_pixbuf.h [new file with mode: 0644]
mlt/src/modules/sdl/Makefile [new file with mode: 0644]
mlt/src/modules/sdl/configure [new file with mode: 0755]
mlt/src/modules/sdl/consumer_sdl.c [new file with mode: 0644]
mlt/src/modules/sdl/consumer_sdl.h [new file with mode: 0644]
mlt/src/modules/sdl/factory.c [new file with mode: 0644]
mlt/src/tests/charlie.c [new file with mode: 0644]
mlt/src/tests/dan.c [new file with mode: 0644]
mlt/src/tests/test.png [new file with mode: 0644]
mlt/src/valerie/Makefile [new file with mode: 0644]
mlt/src/valerie/configure [new file with mode: 0755]
mlt/src/valerie/valerie.c [new file with mode: 0644]
mlt/src/valerie/valerie.h [new file with mode: 0644]
mlt/src/valerie/valerie_notifier.c [new file with mode: 0644]
mlt/src/valerie/valerie_notifier.h [new file with mode: 0644]
mlt/src/valerie/valerie_parser.c [new file with mode: 0644]
mlt/src/valerie/valerie_parser.h [new file with mode: 0644]
mlt/src/valerie/valerie_remote.c [new file with mode: 0644]
mlt/src/valerie/valerie_remote.h [new file with mode: 0644]
mlt/src/valerie/valerie_response.c [new file with mode: 0644]
mlt/src/valerie/valerie_response.h [new file with mode: 0644]
mlt/src/valerie/valerie_socket.c [new file with mode: 0644]
mlt/src/valerie/valerie_socket.h [new file with mode: 0644]
mlt/src/valerie/valerie_status.c [new file with mode: 0644]
mlt/src/valerie/valerie_status.h [new file with mode: 0644]
mlt/src/valerie/valerie_tokeniser.c [new file with mode: 0644]
mlt/src/valerie/valerie_tokeniser.h [new file with mode: 0644]
mlt/src/valerie/valerie_util.c [new file with mode: 0644]
mlt/src/valerie/valerie_util.h [new file with mode: 0644]
src/framework/Makefile [new file with mode: 0644]
src/framework/config.h [new file with mode: 0644]
src/framework/configure [new file with mode: 0755]
src/framework/mlt_consumer.c [new file with mode: 0644]
src/framework/mlt_consumer.h [new file with mode: 0644]
src/framework/mlt_factory.c [new file with mode: 0644]
src/framework/mlt_factory.h [new file with mode: 0644]
src/framework/mlt_filter.c [new file with mode: 0644]
src/framework/mlt_filter.h [new file with mode: 0644]
src/framework/mlt_frame.c [new file with mode: 0644]
src/framework/mlt_frame.h [new file with mode: 0644]
src/framework/mlt_manager.h [new file with mode: 0644]
src/framework/mlt_multitrack.c [new file with mode: 0644]
src/framework/mlt_multitrack.h [new file with mode: 0644]
src/framework/mlt_playlist.c [new file with mode: 0644]
src/framework/mlt_playlist.h [new file with mode: 0644]
src/framework/mlt_producer.c [new file with mode: 0644]
src/framework/mlt_producer.h [new file with mode: 0644]
src/framework/mlt_properties.c [new file with mode: 0644]
src/framework/mlt_properties.h [new file with mode: 0644]
src/framework/mlt_property.c [new file with mode: 0644]
src/framework/mlt_property.h [new file with mode: 0644]
src/framework/mlt_repository.c [new file with mode: 0644]
src/framework/mlt_repository.h [new file with mode: 0644]
src/framework/mlt_service.c [new file with mode: 0644]
src/framework/mlt_service.h [new file with mode: 0644]
src/framework/mlt_tractor.c [new file with mode: 0644]
src/framework/mlt_tractor.h [new file with mode: 0644]
src/framework/mlt_transition.c [new file with mode: 0644]
src/framework/mlt_transition.h [new file with mode: 0644]
src/framework/mlt_types.h [new file with mode: 0644]
src/miracle/configure [new file with mode: 0755]
src/miracle/miracle.c [new file with mode: 0644]
src/miracle/miracle_commands.c [new file with mode: 0644]
src/miracle/miracle_commands.h [new file with mode: 0644]
src/miracle/miracle_connection.c [new file with mode: 0644]
src/miracle/miracle_connection.h [new file with mode: 0644]
src/miracle/miracle_local.c [new file with mode: 0644]
src/miracle/miracle_local.h [new file with mode: 0644]
src/miracle/miracle_log.c [new file with mode: 0644]
src/miracle/miracle_log.h [new file with mode: 0644]
src/miracle/miracle_server.c [new file with mode: 0644]
src/miracle/miracle_server.h [new file with mode: 0644]
src/miracle/miracle_unit.c [new file with mode: 0644]
src/miracle/miracle_unit.h [new file with mode: 0644]
src/miracle/miracle_unit_commands.c [new file with mode: 0644]
src/miracle/miracle_unit_commands.h [new file with mode: 0644]
src/modules/Makefile [new file with mode: 0644]
src/modules/configure [new file with mode: 0755]
src/modules/dv/Makefile [new file with mode: 0644]
src/modules/dv/configure [new file with mode: 0755]
src/modules/dv/factory.c [new file with mode: 0644]
src/modules/dv/producer_libdv.c [new file with mode: 0644]
src/modules/dv/producer_libdv.h [new file with mode: 0644]
src/modules/gtk2/Makefile [new file with mode: 0644]
src/modules/gtk2/configure [new file with mode: 0755]
src/modules/gtk2/factory.c [new file with mode: 0644]
src/modules/gtk2/producer_pixbuf.c [new file with mode: 0644]
src/modules/gtk2/producer_pixbuf.h [new file with mode: 0644]
src/modules/sdl/Makefile [new file with mode: 0644]
src/modules/sdl/configure [new file with mode: 0755]
src/modules/sdl/consumer_sdl.c [new file with mode: 0644]
src/modules/sdl/consumer_sdl.h [new file with mode: 0644]
src/modules/sdl/factory.c [new file with mode: 0644]
src/tests/charlie.c [new file with mode: 0644]
src/tests/dan.c [new file with mode: 0644]
src/tests/test.png [new file with mode: 0644]
src/valerie/Makefile [new file with mode: 0644]
src/valerie/configure [new file with mode: 0755]
src/valerie/valerie.c [new file with mode: 0644]
src/valerie/valerie.h [new file with mode: 0644]
src/valerie/valerie_notifier.c [new file with mode: 0644]
src/valerie/valerie_notifier.h [new file with mode: 0644]
src/valerie/valerie_parser.c [new file with mode: 0644]
src/valerie/valerie_parser.h [new file with mode: 0644]
src/valerie/valerie_remote.c [new file with mode: 0644]
src/valerie/valerie_remote.h [new file with mode: 0644]
src/valerie/valerie_response.c [new file with mode: 0644]
src/valerie/valerie_response.h [new file with mode: 0644]
src/valerie/valerie_socket.c [new file with mode: 0644]
src/valerie/valerie_socket.h [new file with mode: 0644]
src/valerie/valerie_status.c [new file with mode: 0644]
src/valerie/valerie_status.h [new file with mode: 0644]
src/valerie/valerie_tokeniser.c [new file with mode: 0644]
src/valerie/valerie_tokeniser.h [new file with mode: 0644]
src/valerie/valerie_util.c [new file with mode: 0644]
src/valerie/valerie_util.h [new file with mode: 0644]

diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..a275467
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,8 @@
+SUBDIRS = src/framework src/valerie src/modules # src/miracle src/humperdink
+
+all clean dist-clean depend install:
+       list='$(SUBDIRS)'; \
+       for subdir in $$list; do \
+               $(MAKE) -C $$subdir $@; \
+       done
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e72975b
--- /dev/null
+++ b/README
@@ -0,0 +1,115 @@
+README
+------
+
+       This document provides a description of the VPS project organisation.
+
+       It provides *CRITICAL* architecture information, so please read carefully
+       if you plan to extend or use the VPS code base.
+
+Directories
+-----------
+
+       The directory heirarchy is defined as follows:
+
+       + docs                                  - Location of all text and source format 
+                                                         documentation
+       + src                                   - All project source is provided here
+               + client                        - Client API to access the server
+               + framework                     - The media framework - this code is 100% posix
+                                                         and as such contain no implementations 
+                                                         requiring additional libraries
+               + modules                       - All components are defined here with a 
+                                                         subdirectory for each dependency
+                       + bluefish              - Bluefish dependent modules and test code
+                       + ffmpeg                - ffmpeg dependent modules and test code
+                       + mainconcept   - mainconcept dependent modules and test code
+                       + SDL                   - SDL dependent modules and test code
+               + server                        - The server implementation
+
+       Additional subdirectories may be nested below those shown and should be
+       documented in their parent or here.
+
+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.
+
+       Top level usage is:
+
+       ./configure --help                      - report all configure options
+       ./configure --prefix=[dir]      - target install directory (default: /usr/local)
+       ./configure --disable-[mod] - do not compile specified module(s)
+       ./configure --[other]           - pass through to children
+
+Compilation
+-----------
+
+       Makefiles are generated during configuration and these are based on
+       a per directory template which must be provided by the developer.
+
+Installation
+------------
+
+       The install is triggered by running make install or make install-strip
+       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.
+
+       The client produces a single shared object which is installed in 
+       $prefix/lib/ and public header which are installed in 
+       $prefix/include/mlt/client.
+
+       The server produces a single exectuable which is installed in
+       $prefix/bin/. This is linked against the framework shared object and
+       posix libs but not against any of the modules.
+
+       The modules produce a shared object per module and a text file containing
+       a list of modules provided by this build. These are installed in
+       $prefix/share/mlt/. It is at the discretion of the module to install
+       additional support files. 
+       
+       To allow the development of external components, mlt-client-config and
+       mlt-framework-config 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, 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.
+
+Summary
+-------
+
+       1.      The server will interact with public interfaces from the framework only;
+       2.      The modules must expose public framework interfaces only;
+       3.      All modules are dynamically loaded at runtime.
+
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..40b31a4
--- /dev/null
+++ b/configure
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+function show_help
+{
+       cat << EOF
+Funky non-autotool config script for MLT.
+
+       Options are:
+
+       --help                  - this information
+       --prefix=directory      - install prefix for path (default: $prefix)
+EOF
+
+       for i in src/modules/*
+       do
+               [ -d $i ] && echo "     --disable-`basename $i`"
+       done
+
+       echo
+}
+
+# Debug mode
+set +x
+
+# Define build directory for scripts called
+export build_dir=`dirname $0`
+export prefix=/usr/local
+export help=0
+
+# Iterate through arguments
+for i in $*
+do
+       case $i in
+               --help )                help=1 ;;
+               --prefix=* )    prefix="${i#--prefix=}" ;;
+       esac
+done
+
+# Show help if requested
+[ $help = 1 ] && show_help
+
+# Iterate through each of the components
+for i in framework modules valerie miracle humperdink
+do
+       if [ -x src/$i/configure ]
+       then
+               echo "Configuring `basename $i`:"
+               pushd src/$i > /dev/null
+               ./configure $@
+               [ $? != 0 ] && exit 1
+               popd > /dev/null
+       fi
+done
+
diff --git a/mlt/ChangeLog b/mlt/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/mlt/Makefile b/mlt/Makefile
new file mode 100644 (file)
index 0000000..a275467
--- /dev/null
@@ -0,0 +1,8 @@
+SUBDIRS = src/framework src/valerie src/modules # src/miracle src/humperdink
+
+all clean dist-clean depend install:
+       list='$(SUBDIRS)'; \
+       for subdir in $$list; do \
+               $(MAKE) -C $$subdir $@; \
+       done
+
diff --git a/mlt/README b/mlt/README
new file mode 100644 (file)
index 0000000..e72975b
--- /dev/null
@@ -0,0 +1,115 @@
+README
+------
+
+       This document provides a description of the VPS project organisation.
+
+       It provides *CRITICAL* architecture information, so please read carefully
+       if you plan to extend or use the VPS code base.
+
+Directories
+-----------
+
+       The directory heirarchy is defined as follows:
+
+       + docs                                  - Location of all text and source format 
+                                                         documentation
+       + src                                   - All project source is provided here
+               + client                        - Client API to access the server
+               + framework                     - The media framework - this code is 100% posix
+                                                         and as such contain no implementations 
+                                                         requiring additional libraries
+               + modules                       - All components are defined here with a 
+                                                         subdirectory for each dependency
+                       + bluefish              - Bluefish dependent modules and test code
+                       + ffmpeg                - ffmpeg dependent modules and test code
+                       + mainconcept   - mainconcept dependent modules and test code
+                       + SDL                   - SDL dependent modules and test code
+               + server                        - The server implementation
+
+       Additional subdirectories may be nested below those shown and should be
+       documented in their parent or here.
+
+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.
+
+       Top level usage is:
+
+       ./configure --help                      - report all configure options
+       ./configure --prefix=[dir]      - target install directory (default: /usr/local)
+       ./configure --disable-[mod] - do not compile specified module(s)
+       ./configure --[other]           - pass through to children
+
+Compilation
+-----------
+
+       Makefiles are generated during configuration and these are based on
+       a per directory template which must be provided by the developer.
+
+Installation
+------------
+
+       The install is triggered by running make install or make install-strip
+       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.
+
+       The client produces a single shared object which is installed in 
+       $prefix/lib/ and public header which are installed in 
+       $prefix/include/mlt/client.
+
+       The server produces a single exectuable which is installed in
+       $prefix/bin/. This is linked against the framework shared object and
+       posix libs but not against any of the modules.
+
+       The modules produce a shared object per module and a text file containing
+       a list of modules provided by this build. These are installed in
+       $prefix/share/mlt/. It is at the discretion of the module to install
+       additional support files. 
+       
+       To allow the development of external components, mlt-client-config and
+       mlt-framework-config 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, 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.
+
+Summary
+-------
+
+       1.      The server will interact with public interfaces from the framework only;
+       2.      The modules must expose public framework interfaces only;
+       3.      All modules are dynamically loaded at runtime.
+
diff --git a/mlt/configure b/mlt/configure
new file mode 100755 (executable)
index 0000000..40b31a4
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+function show_help
+{
+       cat << EOF
+Funky non-autotool config script for MLT.
+
+       Options are:
+
+       --help                  - this information
+       --prefix=directory      - install prefix for path (default: $prefix)
+EOF
+
+       for i in src/modules/*
+       do
+               [ -d $i ] && echo "     --disable-`basename $i`"
+       done
+
+       echo
+}
+
+# Debug mode
+set +x
+
+# Define build directory for scripts called
+export build_dir=`dirname $0`
+export prefix=/usr/local
+export help=0
+
+# Iterate through arguments
+for i in $*
+do
+       case $i in
+               --help )                help=1 ;;
+               --prefix=* )    prefix="${i#--prefix=}" ;;
+       esac
+done
+
+# Show help if requested
+[ $help = 1 ] && show_help
+
+# Iterate through each of the components
+for i in framework modules valerie miracle humperdink
+do
+       if [ -x src/$i/configure ]
+       then
+               echo "Configuring `basename $i`:"
+               pushd src/$i > /dev/null
+               ./configure $@
+               [ $? != 0 ] && exit 1
+               popd > /dev/null
+       fi
+done
+
diff --git a/mlt/src/framework/Makefile b/mlt/src/framework/Makefile
new file mode 100644 (file)
index 0000000..e2d60ee
--- /dev/null
@@ -0,0 +1,38 @@
+
+FRAMEWORK_OBJS = mlt_frame.o \
+                                mlt_property.o \
+                                mlt_properties.o \
+                                mlt_service.o \
+                                mlt_producer.o \
+                                mlt_multitrack.o \
+                                mlt_consumer.o \
+                                mlt_filter.o \
+                                mlt_transition.o \
+                                mlt_tractor.o \
+                                mlt_factory.o \
+                                mlt_repository.o
+
+OBJS = $(FRAMEWORK_OBJS)
+
+SRCS := $(OBJS:.o=.c)
+
+CFLAGS=-g -Wall -D_FILE_OFFSET_BITS=64 -pthread 
+
+all:   libmlt.a
+
+libmlt.a: $(OBJS)
+               $(AR) rvu $@ $(OBJS)
+               ranlib $@
+
+depend:        $(SRCS)
+               $(CC) -MM $(CFLAGS) $^ 1>.depend
+
+dist-clean:    clean
+               rm -f .depend
+
+clean: 
+               rm -f $(FRAMEWORK_OBJS) libmlt.a
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/mlt/src/framework/config.h b/mlt/src/framework/config.h
new file mode 100644 (file)
index 0000000..fec9861
--- /dev/null
@@ -0,0 +1,10 @@
+/** GENERATED FILE - DON'T EDIT */
+
+#ifndef _MLT_CONFIG_H_
+#define _MLT_CONFIG_H_
+
+#define PREFIX                 "/usr/local"
+#define PREFIX_DATA            PREFIX "/share"
+
+#endif
+
diff --git a/mlt/src/framework/configure b/mlt/src/framework/configure
new file mode 100755 (executable)
index 0000000..a9bf588
--- /dev/null
@@ -0,0 +1 @@
+#!/bin/bash
diff --git a/mlt/src/framework/mlt_consumer.c b/mlt/src/framework/mlt_consumer.c
new file mode 100644 (file)
index 0000000..635ad65
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * mlt_consumer.c -- abstraction for all consumer services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "mlt_consumer.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/** Public final methods
+*/
+
+int mlt_consumer_init( mlt_consumer this, void *child )
+{
+       memset( this, 0, sizeof( struct mlt_consumer_s ) );
+       this->child = child;
+       return mlt_service_init( &this->parent, this );
+}
+
+/** Get the parent service object.
+*/
+
+mlt_service mlt_consumer_service( mlt_consumer this )
+{
+       return &this->parent;
+}
+
+/** 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 );
+}
+
+/** Close the consumer.
+*/
+
+void mlt_consumer_close( mlt_consumer this )
+{
+       if ( this->close != NULL )
+               this->close( this );
+       else
+               mlt_service_close( &this->parent );
+}
+
diff --git a/mlt/src/framework/mlt_consumer.h b/mlt/src/framework/mlt_consumer.h
new file mode 100644 (file)
index 0000000..cbe9078
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * mlt_consumer.h -- abstraction for all consumer services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_CONSUMER_H_
+#define _MLT_CONSUMER_H_
+
+#include "mlt_service.h"
+
+/** The interface definition for all consumers.
+*/
+
+struct mlt_consumer_s
+{
+       // We're implementing service here
+       struct mlt_service_s parent;
+
+       // public virtual
+       void ( *close )( mlt_consumer );
+
+       // Private data
+       void *private;
+       void *child;
+};
+
+/** Public final methods
+*/
+
+extern int mlt_consumer_init( mlt_consumer this, void *child );
+extern mlt_service mlt_consumer_service( mlt_consumer this );
+extern int mlt_consumer_connect( mlt_consumer this, mlt_service producer );
+extern void mlt_consumer_close( mlt_consumer );
+
+#endif
diff --git a/mlt/src/framework/mlt_factory.c b/mlt/src/framework/mlt_factory.c
new file mode 100644 (file)
index 0000000..3b40464
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * mlt_factory.c -- the factory method interfaces
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "mlt_factory.h"
+#include "mlt_repository.h"
+
+#include <stdlib.h>
+
+/** Singleton repositories
+*/
+
+static mlt_repository producers = NULL;
+static mlt_repository filters = NULL;
+static mlt_repository transitions = NULL;
+static mlt_repository consumers = NULL;
+
+/** Construct the factories.
+*/
+
+int mlt_factory_init( )
+{
+       producers = mlt_repository_init( PREFIX_DATA "/producers.dat", "mlt_create_producer" );
+       filters = mlt_repository_init( PREFIX_DATA "/filters.dat", "mlt_create_filter" );
+       transitions = mlt_repository_init( PREFIX_DATA "/transitions.dat", "mlt_create_transition" );
+       consumers = mlt_repository_init( PREFIX_DATA "/consumers.dat", "mlt_create_consumer" );
+       return 0;
+}
+
+/** Fetch a producer from the repository.
+*/
+
+mlt_producer mlt_factory_producer( char *service, void *input )
+{
+       return ( mlt_producer )mlt_repository_fetch( producers, service, input );
+}
+
+/** Fetch a filter from the repository.
+*/
+
+mlt_filter mlt_factory_filter( char *service, void *input )
+{
+       return ( mlt_filter )mlt_repository_fetch( filters, service, input );
+}
+
+/** Fetch a transition from the repository.
+*/
+
+mlt_transition mlt_transition_filter( char *service, void *input )
+{
+       return ( mlt_transition )mlt_repository_fetch( transitions, service, input );
+}
+
+/** Fetch a consumer from the repository
+*/
+
+mlt_consumer mlt_factory_consumer( char *service, void *input )
+{
+       return ( mlt_consumer )mlt_repository_fetch( consumers, service, input );
+}
+
+/** Close the factory.
+*/
+
+void mlt_factory_close( )
+{
+       mlt_repository_close( producers );
+       mlt_repository_close( filters );
+       mlt_repository_close( transitions );
+       mlt_repository_close( consumers );
+}
+
diff --git a/mlt/src/framework/mlt_factory.h b/mlt/src/framework/mlt_factory.h
new file mode 100644 (file)
index 0000000..4cece1d
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * mlt_factory.h -- the factory method interfaces
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_FACTORY_H
+#define _MLT_FACTORY_H
+
+#include "mlt_types.h"
+
+extern int mlt_factory_init( );
+extern mlt_producer mlt_factory_producer( char *name, void *input );
+extern mlt_filter mlt_factory_filter( char *name, void *input );
+extern mlt_transition mlt_factory_transition( char *name, void *input );
+extern mlt_consumer mlt_factory_consumer( char *name, void *input );
+extern void mlt_factory_close( );
+
+#endif
diff --git a/mlt/src/framework/mlt_filter.c b/mlt/src/framework/mlt_filter.c
new file mode 100644 (file)
index 0000000..22fefe2
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * mlt_filter.c -- abstraction for all filter services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 )
+       {
+               service->get_frame = filter_get_frame;
+               return 0;
+       }
+       return 1;
+}
+
+/** Get the service associated to this filter
+*/
+
+mlt_service mlt_filter_service( mlt_filter this )
+{
+       return &this->parent;
+}
+
+/** 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 )
+       {
+               this->producer = producer;
+               this->track = index;
+               this->in = 0;
+               this->out = 0;
+       }
+       
+       return ret;
+}
+
+/** Tune the in/out points.
+*/
+
+void mlt_filter_set_in_and_out( mlt_filter this, mlt_timecode in, mlt_timecode out )
+{
+       this->in = in;
+       this->out = out;
+}
+
+/** Return the track that this filter is operating on.
+*/
+
+int mlt_filter_get_track( mlt_filter this )
+{
+       return this->track;
+}
+
+/** Get the in point.
+*/
+
+mlt_timecode mlt_filter_get_in( mlt_filter this )
+{
+       return this->in;
+}
+
+/** Get the out point.
+*/
+
+mlt_timecode mlt_filter_get_out( mlt_filter this )
+{
+       return this->out;
+}
+
+/** Process the frame.
+*/
+
+static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
+{
+       if ( 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;
+       
+       // If the frame request is for this filters track, we need to process it
+       if ( index == this->track )
+       {
+               int ret = mlt_service_get_frame( this->producer, frame, index );
+               if ( ret == 0 )
+               {
+                       if ( !mlt_frame_is_test_card( *frame ) )
+                       {
+                               mlt_timecode timecode = mlt_frame_get_timecode( *frame );
+                               if ( timecode >= this->in && ( this->out == 0 || timecode < this->out ) )
+                                       *frame = filter_process( this, *frame );
+                       }
+                       return 0;
+               }
+               else
+               {
+                       *frame = mlt_frame_init( );
+                       return 0;
+               }
+       }
+       else
+       {
+               return mlt_service_get_frame( this->producer, frame, index );
+       }
+}
+
+/** Close the filter.
+*/
+
+void mlt_filter_close( mlt_filter this )
+{
+       if ( this->close != NULL )
+               this->close( this );
+       else
+               mlt_service_close( &this->parent );
+}
+
diff --git a/mlt/src/framework/mlt_filter.h b/mlt/src/framework/mlt_filter.h
new file mode 100644 (file)
index 0000000..99212a9
--- /dev/null
@@ -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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 );
+
+       // track and in/out points
+       mlt_service producer;
+       int track;
+       mlt_timecode in;
+       mlt_timecode out;
+
+       // Protected
+       void *child;
+};
+
+/** Public final methods
+*/
+
+extern int mlt_filter_init( mlt_filter this, void *child );
+extern mlt_service mlt_filter_service( mlt_filter this );
+extern int mlt_filter_connect( mlt_filter this, mlt_service producer, int index );
+extern void mlt_filter_set_in_and_out( mlt_filter this, mlt_timecode in, mlt_timecode out );
+extern int mlt_filter_get_track( mlt_filter this );
+extern mlt_timecode mlt_filter_get_in( mlt_filter this );
+extern mlt_timecode mlt_filter_get_out( mlt_filter this );
+extern void mlt_filter_close( mlt_filter );
+
+#endif
diff --git a/mlt/src/framework/mlt_frame.c b/mlt/src/framework/mlt_frame.c
new file mode 100644 (file)
index 0000000..9c9eac1
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * mlt_frame.c -- interface for all frame classes
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "mlt_frame.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct
+{
+       mlt_image_format vfmt;
+       int width;
+       int height;
+       uint8_t *image;
+       uint8_t *alpha;
+       mlt_audio_format afmt;
+       int16_t *audio;
+}
+frame_test;
+
+static frame_test test_card = { mlt_image_none, 0, 0, NULL, NULL, mlt_audio_none, NULL };
+
+/** Constructor for a frame.
+*/
+
+mlt_frame mlt_frame_init( )
+{
+       // Allocate a frame
+       mlt_frame this = calloc( sizeof( struct mlt_frame_s ), 1 );
+
+       if ( this != NULL )
+       {
+               // Initialise the properties
+               mlt_properties properties = &this->parent;
+               mlt_properties_init( properties, this );
+
+               // Set default properties on the frame
+               mlt_properties_set_timecode( properties, "timecode", 0.0 );
+               mlt_properties_set_data( properties, "image", NULL, 0, NULL, NULL );
+               mlt_properties_set_int( properties, "width", 720 );
+               mlt_properties_set_int( properties, "height", 576 );
+               mlt_properties_set_double( properties, "aspect_ratio", 4.0 / 3.0 );
+               mlt_properties_set_data( properties, "audio", NULL, 0, NULL, NULL );
+               mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL );
+       }
+       return this;
+}
+
+/** Fetch the frames properties.
+*/
+
+mlt_properties mlt_frame_properties( mlt_frame this )
+{
+       return &this->parent;
+}
+
+/** Check if we have a way to derive something other than a test card.
+*/
+
+int mlt_frame_is_test_card( mlt_frame this )
+{
+       return this->stack_get_image_size == 0;
+}
+
+/** Get the aspect ratio of the frame.
+*/
+
+double mlt_frame_get_aspect_ratio( mlt_frame this )
+{
+       mlt_properties properties = mlt_frame_properties( this );
+       return mlt_properties_get_double( properties, "aspect_ratio" );
+}
+
+/** Set the aspect ratio of the frame.
+*/
+
+int mlt_frame_set_aspect_ratio( mlt_frame this, double value )
+{
+       mlt_properties properties = mlt_frame_properties( this );
+       return mlt_properties_set_double( properties, "aspect_ratio", value );
+}
+
+/** Get the timecode of this frame.
+*/
+
+mlt_timecode mlt_frame_get_timecode( mlt_frame this )
+{
+       mlt_properties properties = mlt_frame_properties( this );
+       return mlt_properties_get_timecode( properties, "timecode" );
+}
+
+/** Set the timecode of this frame.
+*/
+
+int mlt_frame_set_timecode( mlt_frame this, mlt_timecode value )
+{
+       mlt_properties properties = mlt_frame_properties( this );
+       return mlt_properties_set_timecode( properties, "timecode", value );
+}
+
+/** Stack a get_image callback.
+*/
+
+int mlt_frame_push_get_image( mlt_frame this, mlt_get_image get_image )
+{
+       int ret = this->stack_get_image_size >= 10;
+       if ( ret == 0 )
+               this->stack_get_image[ this->stack_get_image_size ++ ] = get_image;
+       return ret;
+}
+
+/** Pop a get_image callback.
+*/
+
+mlt_get_image mlt_frame_pop_get_image( mlt_frame this )
+{
+       mlt_get_image result = NULL;
+       if ( this->stack_get_image_size > 0 )
+               result = this->stack_get_image[ -- this->stack_get_image_size ];
+       return result;
+}
+
+/** Push a frame.
+*/
+
+int mlt_frame_push_frame( mlt_frame this, mlt_frame that )
+{
+       int ret = this->stack_frame_size >= 10;
+       if ( ret == 0 )
+               this->stack_frame[ this->stack_frame_size ++ ] = that;
+       return ret;
+}
+
+/** Pop a frame.
+*/
+
+mlt_frame mlt_frame_pop_frame( mlt_frame this )
+{
+       mlt_frame result = NULL;
+       if ( this->stack_frame_size > 0 )
+               result = this->stack_frame[ -- this->stack_frame_size ];
+       return result;
+}
+
+int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
+{
+       mlt_properties properties = mlt_frame_properties( this );
+       mlt_get_image get_image = mlt_frame_pop_get_image( this );
+       
+       if ( get_image != NULL )
+       {
+               return get_image( this, buffer, format, width, height, writable );
+       }
+       else if ( mlt_properties_get_data( properties, "image", NULL ) != NULL )
+       {
+               *format = mlt_image_yuv422;
+               *buffer = mlt_properties_get_data( properties, "image", NULL );
+               *width = mlt_properties_get_int( properties, "width" );
+               *height = mlt_properties_get_int( properties, "height" );
+       }
+       else
+       {
+               if ( test_card.vfmt != *format )
+               {
+                       uint8_t *p;
+                       uint8_t *q;
+                       
+                       test_card.vfmt = *format;
+                       test_card.width = 720;
+                       test_card.height = 576;
+
+                       switch( *format )
+                       {
+                               case mlt_image_none:
+                                       break;
+                               case mlt_image_rgb24:
+                                       test_card.image = realloc( test_card.image, test_card.width * test_card.height * 3 );
+                                       memset( test_card.image, 255, test_card.width * test_card.height * 3 );
+                                       break;
+                               case mlt_image_rgb24a:
+                                       test_card.image = realloc( test_card.image, test_card.width * test_card.height * 4 );
+                                       memset( test_card.image, 255, test_card.width * test_card.height * 4 );
+                                       break;
+                               case mlt_image_yuv422:
+                                       test_card.image = realloc( test_card.image, test_card.width * test_card.height * 2 );
+                                       p = test_card.image;
+                                       q = test_card.image + test_card.width * test_card.height * 2;
+                                       while ( p != q )
+                                       {
+                                               *p ++ = 255;
+                                               *p ++ = 128;
+                                       }
+                                       break;
+                               case mlt_image_yuv420p:
+                                       test_card.image = realloc( test_card.image, test_card.width * test_card.height * 3 / 2 );
+                                       memset( test_card.image, 255, test_card.width * test_card.height * 3 / 2 );
+                                       break;
+                       }
+               }
+
+               *width = test_card.width;
+               *height = test_card.height;
+               *buffer = test_card.image;
+       }
+
+       return 0;
+}
+
+uint8_t *mlt_frame_get_alpha_mask( mlt_frame this )
+{
+       if ( this->get_alpha_mask != NULL )
+               return this->get_alpha_mask( this );
+       return test_card.alpha;
+}
+
+int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
+{
+       if ( this->get_audio != NULL )
+       {
+               return this->get_audio( this, buffer, format, frequency, channels, samples );
+       }
+       else
+       {
+               if ( test_card.afmt != *format )
+               {
+                       test_card.afmt = *format;
+                       test_card.audio = realloc( test_card.audio, 1920 * 2 * sizeof( int16_t ) );
+                       memset( test_card.audio, 0, 1920 * 2 * sizeof( int16_t ) );
+               }
+               
+               *buffer = test_card.audio;
+               *frequency = 48000;
+               *channels = 2;
+               *samples = 1920;
+       }
+       return 0;
+}
+
+void mlt_frame_close( mlt_frame this )
+{
+       mlt_frame frame = mlt_frame_pop_frame( this );
+       
+       while ( frame != NULL )
+       {
+               mlt_frame_close( frame);
+               frame = mlt_frame_pop_frame( this );
+       }
+       
+       mlt_properties_close( &this->parent );
+
+       free( this );
+}
+
+/***** convenience functions *****/
+#define RGB2YUV(r, g, b, y, u, v)\
+  y = (306*r + 601*g + 117*b)  >> 10;\
+  u = ((-172*r - 340*g + 512*b) >> 10)  + 128;\
+  v = ((512*r - 429*g - 83*b) >> 10) + 128;\
+  y = y < 0 ? 0 : y;\
+  u = u < 0 ? 0 : u;\
+  v = v < 0 ? 0 : v;\
+  y = y > 255 ? 255 : y;\
+  u = u > 255 ? 255 : u;\
+  v = v > 255 ? 255 : v
+
+int mlt_convert_rgb24a_to_yuv422( uint8_t *rgba, int width, int height, int stride, uint8_t *yuv, uint8_t *alpha )
+{
+       int ret = 0;
+       register int y0, y1, u0, u1, v0, v1;
+       register int r, g, b;
+       register uint8_t *d = yuv;
+       register int i, j;
+
+       for ( i = 0; i < height; i++ )
+       {
+               register uint8_t *s = rgba + ( stride * i );
+               for ( j = 0; j < ( width / 2 ); j++ )
+               {
+                       r = *s++;
+                       g = *s++;
+                       b = *s++;
+                       *alpha++ = *s++;
+                       RGB2YUV (r, g, b, y0, u0 , v0);
+                       r = *s++;
+                       g = *s++;
+                       b = *s++;
+                       *alpha++ = *s++;
+                       RGB2YUV (r, g, b, y1, u1 , v1);
+                       *d++ = y0;
+                       *d++ = (u0+u1) >> 1;
+                       *d++ = y1;
+                       *d++ = (v0+v1) >> 1;
+               }
+       }
+       return ret;
+}
+
+int mlt_convert_rgb24_to_yuv422( uint8_t *rgb, int width, int height, int stride, uint8_t *yuv )
+{
+       int ret = 0;
+       register int y0, y1, u0, u1, v0, v1;
+       register int r, g, b;
+       register uint8_t *d = yuv;
+       register int i, j;
+
+       for ( i = 0; i < height; i++ )
+       {
+               register uint8_t *s = rgb + ( stride * i );
+               for ( j = 0; j < ( width / 2 ); j++ )
+               {
+                       r = *s++;
+                       g = *s++;
+                       b = *s++;
+                       RGB2YUV (r, g, b, y0, u0 , v0);
+                       r = *s++;
+                       g = *s++;
+                       b = *s++;
+                       RGB2YUV (r, g, b, y1, u1 , v1);
+                       *d++ = y0;
+                       *d++ = (u0+u1) >> 1;
+                       *d++ = y1;
+                       *d++ = (v0+v1) >> 1;
+               }
+       }
+       return ret;
+}
+
+int mlt_frame_composite_yuv( mlt_frame this, mlt_frame that, int x, int y, float weight )
+{
+       int ret = 0;
+       int x_start = 0;
+       int width_src, height_src;
+       int width_dest, height_dest;
+       mlt_image_format format_src, format_dest;
+       uint8_t *p_src, *p_dest;
+       int x_end;
+       int i, j;
+       int stride_src;
+       int stride_dest;
+
+       format_src = mlt_image_yuv422;
+       format_dest = mlt_image_yuv422;
+       
+       mlt_frame_get_image( this, &p_dest, &format_dest, &width_dest, &height_dest, 1 /* writable */ );
+       mlt_frame_get_image( that, &p_src, &format_src, &width_src, &height_src, 0 /* writable */ );
+       
+       x_end = width_src;
+       
+       stride_src = width_src * 2;
+       stride_dest = width_dest * 2;
+       uint8_t *lower = p_dest;
+       uint8_t *upper = p_dest + height_dest * stride_dest;
+
+       p_dest += ( y * stride_dest ) + ( x * 2 );
+
+       if ( x < 0 )
+       {
+               x_start = -x;
+               x_end += x_start;
+       }
+
+       uint8_t *z = mlt_frame_get_alpha_mask( that );
+
+       for ( i = 0; i < height_src; i++ )
+       {
+               uint8_t *p = p_src;
+               uint8_t *q = p_dest;
+               uint8_t *o = p_dest;
+
+               for ( j = 0; j < width_src; j ++ )
+               {
+                       if ( q >= lower && q < upper && j >= x_start && j < x_end )
+                       {
+                               uint8_t y = *p ++;
+                               uint8_t uv = *p ++;
+                               uint8_t a = ( z == NULL ) ? 255 : *z ++;
+                               float value = ( weight * ( float ) a / 255.0 );
+                               *o ++ = (uint8_t)( y * value + *q++ * ( 1 - value ) );
+                               *o ++ = (uint8_t)( uv * value + *q++ * ( 1 - value ) );
+                       }
+                       else
+                       {
+                               p += 2;
+                               o += 2;
+                               q += 2;
+                               if ( z != NULL )
+                                       z += 1;
+                       }
+               }
+
+               p_src += stride_src;
+               p_dest += stride_dest;
+       }
+
+       return ret;
+}
+
diff --git a/mlt/src/framework/mlt_frame.h b/mlt/src/framework/mlt_frame.h
new file mode 100644 (file)
index 0000000..fd86f23
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * mlt_frame.h -- interface for all frame classes
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_FRAME_H_
+#define _MLT_FRAME_H_
+
+#include "mlt_properties.h"
+
+typedef enum
+{
+       mlt_image_none = 0,
+       mlt_image_rgb24,
+       mlt_image_rgb24a,
+       mlt_image_yuv422,
+       mlt_image_yuv420p
+}
+mlt_image_format;
+
+typedef enum
+{
+       mlt_audio_none = 0,
+       mlt_audio_pcm
+}
+mlt_audio_format;
+
+typedef int ( *mlt_get_image )( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable );
+
+struct mlt_frame_s
+{
+       // We're extending properties here
+       struct mlt_properties_s parent;
+
+       // Virtual methods
+       int ( *get_audio )( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
+       uint8_t * ( *get_alpha_mask )( mlt_frame this );
+       
+       // Private properties
+       mlt_get_image stack_get_image[ 10 ];
+       int stack_get_image_size;
+       mlt_frame stack_frame[ 10 ];
+       int stack_frame_size;
+};
+
+extern mlt_frame mlt_frame_init( );
+extern mlt_properties mlt_frame_properties( mlt_frame this );
+extern int mlt_frame_is_test_card( mlt_frame this );
+extern double mlt_frame_get_aspect_ratio( mlt_frame this );
+extern int mlt_frame_set_aspect_ratio( mlt_frame this, double value );
+extern mlt_timecode mlt_frame_get_timecode( mlt_frame this );
+extern int mlt_frame_set_timecode( mlt_frame this, mlt_timecode value );
+
+extern int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable );
+extern uint8_t *mlt_frame_get_alpha_mask( mlt_frame this );
+extern int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
+
+extern int mlt_frame_push_get_image( mlt_frame this, mlt_get_image get_image );
+extern mlt_get_image mlt_frame_pop_get_image( mlt_frame this );
+extern int mlt_frame_push_frame( mlt_frame this, mlt_frame that );
+extern mlt_frame mlt_frame_pop_frame( mlt_frame this );
+extern void mlt_frame_close( mlt_frame this );
+
+/* convenience functions */
+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_frame_composite_yuv( mlt_frame this, mlt_frame that, int x, int y, float weight );
+    
+#endif
+
diff --git a/mlt/src/framework/mlt_manager.h b/mlt/src/framework/mlt_manager.h
new file mode 100644 (file)
index 0000000..1567e64
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * mlt_manager.h -- manager service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_MANAGER_H_
+#define _MLT_MANAGER_H_
+
+mlt_producer mlt_manager_init( char **config );
+
+#endif
diff --git a/mlt/src/framework/mlt_multitrack.c b/mlt/src/framework/mlt_multitrack.c
new file mode 100644 (file)
index 0000000..77158c7
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * mlt_multitrack.c -- multitrack service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "mlt_multitrack.h"
+#include "mlt_frame.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/** Private definition.
+*/
+
+struct mlt_multitrack_s
+{
+       // We're extending producer here
+       struct mlt_producer_s parent;
+       mlt_producer *list;
+       int size;
+       int count;
+};
+
+/** Forward reference.
+*/
+
+static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index );
+
+/** Constructor.
+*/
+
+mlt_multitrack mlt_multitrack_init( )
+{
+       // Allocate the multitrack object
+       mlt_multitrack this = calloc( sizeof( struct mlt_multitrack_s ), 1 );
+
+       if ( this != NULL )
+       {
+               mlt_producer producer = &this->parent;
+               if ( mlt_producer_init( producer, this ) == 0 )
+               {
+                       producer->get_frame = producer_get_frame;
+               }
+               else
+               {
+                       free( this );
+                       this = NULL;
+               }
+       }
+       
+       return this;
+}
+
+/** Get the producer associated to this multitrack.
+*/
+
+mlt_producer mlt_multitrack_producer( mlt_multitrack this )
+{
+       return &this->parent;
+}
+
+/** Get the service associated this multitrack.
+*/
+
+mlt_service mlt_multitrack_service( mlt_multitrack this )
+{
+       return mlt_producer_service( mlt_multitrack_producer( this ) );
+}
+
+/** Get the properties associated this multitrack.
+*/
+
+mlt_properties mlt_multitrack_properties( mlt_multitrack this )
+{
+       return mlt_service_properties( mlt_multitrack_service( this ) );
+}
+
+/** Initialise timecode related information.
+*/
+
+static void mlt_multitrack_refresh( mlt_multitrack this )
+{
+       int i = 0;
+
+       // Obtain the properties of this multitrack
+       mlt_properties properties = mlt_multitrack_properties( this );
+
+       // We need to ensure that the multitrack reports the longest track as its length
+       mlt_timecode length = 0;
+
+       // We need to ensure that fps are the same on all services
+       double fps = 0;
+       
+       // Obtain stats on all connected services
+       for ( i = 0; i < this->count; i ++ )
+       {
+               // Get the producer from this index
+               mlt_producer producer = this->list[ i ];
+
+               // If it's allocated then, update our stats
+               if ( producer != NULL )
+               {
+                       // Determine the longest length
+                       length = mlt_producer_get_length( producer ) > length ? mlt_producer_get_length( producer ) : length;
+                       
+                       // Handle fps
+                       if ( fps == 0 )
+                       {
+                               // This is the first producer, so it controls the fps
+                               fps = mlt_producer_get_fps( producer );
+                       }
+                       else if ( fps != mlt_producer_get_fps( producer ) )
+                       {
+                               // Generate a warning for now - the following attempt to fix may fail
+                               fprintf( stderr, "Warning: fps mismatch on track %d\n", i );
+
+                               // It should be safe to impose fps on an image producer, but not necessarily safe for video
+                               mlt_properties_set_double( mlt_producer_properties( producer ), "fps", fps );
+                       }
+               }
+       }
+
+       // Update multitrack properties now - we'll not destroy the in point here
+       mlt_properties_set_timecode( properties, "length", length );
+       mlt_properties_set_timecode( properties, "out", length );
+       mlt_properties_set_timecode( properties, "playtime", length - mlt_properties_get_timecode( properties, "in" ) );
+}
+
+/** Connect a producer to a given track.
+*/
+
+int mlt_multitrack_connect( mlt_multitrack this, mlt_producer producer, int track )
+{
+       // Connect to the producer to ourselves at the specified track
+       int result = mlt_service_connect_producer( mlt_multitrack_service( this ), mlt_producer_service( producer ), track );
+
+       if ( result == 0 )
+       {
+               // Resize the producer list if need be
+               if ( track >= this->size )
+               {
+                       int i;
+                       this->list = realloc( this->list, ( track + 10 ) * sizeof( mlt_producer ) );
+                       for ( i = this->size; i < track + 10; i ++ )
+                               this->list[ i ] = NULL;
+                       this->size = track + 10;
+               }
+               
+               // Assign the track in our list here
+               this->list[ track ] = producer;
+               
+               // Increment the track count if need be
+               if ( track >= this->count )
+                       this->count = track + 1;
+                       
+               // Refresh our stats
+               mlt_multitrack_refresh( this );
+       }
+
+       return result;
+}
+
+/** Get frame method.
+
+       Special case here: The multitrack must be used in a conjunction with a downstream
+       tractor-type service, ie:
+
+       Producer1 \
+       Producer2 - multitrack - { filters/transitions } - tractor - consumer
+       Producer3 /
+
+       The get_frame of a tractor pulls frames from it's connected service on all tracks and 
+       will terminate as soon as it receives a test card with a last_track property. The 
+       important case here is that the mulitrack does not move to the next frame until all
+       tracks have been pulled. 
+
+       Reasoning: In order to seek on a network such as above, the multitrack needs to ensure
+       that all producers are positioned on the same frame. It uses the 'last track' logic
+       to determine when to move to the next frame.
+
+       Flaw: if a transition is configured to read from a b-track which happens to trigger
+       the last frame logic (ie: it's configured incorrectly), then things are going to go
+       out of sync.
+
+       See playlist logic too.
+*/
+
+static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index )
+{
+       // Get the mutiltrack object
+       mlt_multitrack this = parent->child;
+
+       // Check if we have a track for this index
+       if ( index < this->count && this->list[ index ] != NULL )
+       {
+               // Get the producer for this track
+               mlt_producer producer = this->list[ index ];
+
+               // Obtain the current timecode
+               uint64_t position = mlt_producer_frame( parent );
+
+               // Make sure we're at the same point
+               mlt_producer_seek_frame( producer, position );
+
+               // Get the frame from the producer
+               mlt_service_get_frame( mlt_producer_service( producer ), frame, 0 );
+       }
+       else
+       {
+               // Generate a test frame
+               *frame = mlt_frame_init( );
+
+               // Let tractor know if we've reached the end
+               mlt_properties_set_int( mlt_frame_properties( *frame ), "last_track", index >= this->count );
+
+               // Update timecode on the frame we're creating
+               mlt_frame_set_timecode( *frame, mlt_producer_position( parent ) );
+
+               // Move on to the next frame
+               if ( index >= this->count )
+                       mlt_producer_prepare_next( parent );
+       }
+
+       fprintf( stderr, "timestamp for %d = %f\n", index, ( float )mlt_frame_get_timecode( *frame ) );
+
+       return 0;
+}
+
+/** Close this instance.
+*/
+
+void mlt_multitrack_close( mlt_multitrack this )
+{
+       // Close the producer
+       mlt_producer_close( &this->parent );
+
+       // Free the list
+       free( this->list );
+
+       // Free the object
+       free( this );
+}
diff --git a/mlt/src/framework/mlt_multitrack.h b/mlt/src/framework/mlt_multitrack.h
new file mode 100644 (file)
index 0000000..9f85fc1
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * mlt_multitrack.h -- multitrack service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_MULITRACK_H_
+#define _MLT_MULITRACK_H_
+
+#include "mlt_producer.h"
+
+/** Public final methods
+*/
+
+extern mlt_multitrack mlt_multitrack_init( );
+extern mlt_producer mlt_multitrack_producer( mlt_multitrack this );
+extern mlt_service mlt_multitrack_service( mlt_multitrack this );
+extern int mlt_multitrack_connect( mlt_multitrack this, mlt_producer producer, int track );
+extern void mlt_multitrack_close( mlt_multitrack this );
+
+#endif
+
diff --git a/mlt/src/framework/mlt_playlist.c b/mlt/src/framework/mlt_playlist.c
new file mode 100644 (file)
index 0000000..ffcb3d5
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * mlt_playlist.c -- playlist service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "mlt_playlist.h"
+
+/** Private definition.
+*/
+
+struct mlt_playlist_s
+{
+       struct mlt_producer_s parent;
+       int count;
+       int track;
+};
+
+/** Constructor.
+
+       TODO: Override and implement all transport related method.
+       TODO: Override and implement a time code normalising service get_frame
+*/
+
+mlt_playlist mlt_playlist_init( )
+{
+       mlt_playlist this = calloc( sizeof( struct mlt_playlist_s ), 1 );
+       if ( this != NULL )
+       {
+               mlt_producer producer = &this->parent;
+               if ( mlt_producer_init( producer, this ) != 0 )
+               {
+                       free( this );
+                       this = NULL;
+               }
+       }
+       
+       return this;
+}
+
+/** Get the producer associated to this playlist.
+*/
+
+mlt_producer mlt_playlist_producer( mlt_playlist this )
+{
+       return &this->parent;
+}
+
+/** Get the service associated to this playlist.
+*/
+
+mlt_service mlt_playlist_service( mlt_playlist this )
+{
+       return mlt_producer_service( &this->parent );
+}
+
+/** Append a producer to the playlist.
+
+       TODO: Implement
+       TODO: Extract length information from the producer.
+*/
+
+int mlt_playlist_append( mlt_playlist this, mlt_producer producer )
+{
+       return 0;
+}
+
+/** Append a blank to the playlist of a given length.
+
+       TODO: Implement
+*/
+
+int mlt_playlist_blank( mlt_playlist this, mlt_timecode length )
+{
+       return 0;
+}
+
+/** Close the playlist.
+*/
+
+mlt_playlist_close( mlt_playlist this )
+{
+       mlt_producer_close( &this->parent );
+       free( this );
+}
diff --git a/mlt/src/framework/mlt_playlist.h b/mlt/src/framework/mlt_playlist.h
new file mode 100644 (file)
index 0000000..aa916c8
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * mlt_playlist.h -- playlist service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_PLAYLIST_H_
+#define _MLT_PLAYLIST_H_
+
+#include "mlt_producer.h"
+
+/** Public final methods
+*/
+
+extern mlt_playlist mlt_playlist_init( );
+extern mlt_producer mlt_playlist_producer( mlt_playlist this );
+extern mlt_service mlt_playlist_service( mlt_playlist this );
+extern int mlt_playlist_append( mlt_playlist this, mlt_producer producer );
+extern int mlt_playlist_pad( mlt_playlist this, mlt_timecode length );
+extern mlt_playlist_close( mlt_playlist this );
+
+#endif
+
diff --git a/mlt/src/framework/mlt_producer.c b/mlt/src/framework/mlt_producer.c
new file mode 100644 (file)
index 0000000..91e3989
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * mlt_producer.c -- abstraction for all producer services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "mlt_producer.h"
+#include "mlt_frame.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+/** Forward references.
+*/
+
+static int producer_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
+
+/** Constructor
+*/
+
+int mlt_producer_init( mlt_producer this, void *child )
+{
+       // Initialise the producer
+       memset( this, 0, sizeof( struct mlt_producer_s ) );
+       
+       // Associate with the child
+       this->child = child;
+
+       // Initialise the service
+       if ( mlt_service_init( &this->parent, this ) == 0 )
+       {
+               // The parent is the service
+               mlt_service parent = &this->parent;
+
+               // Get the properties of the parent
+               mlt_properties properties = mlt_service_properties( parent );
+
+               // Set the default properties
+               mlt_properties_set_timecode( properties, "position", 0.0 );
+               mlt_properties_set_double( properties, "frame", 1 );
+               mlt_properties_set_double( properties, "fps", 25.0 );
+               mlt_properties_set_double( properties, "speed", 1.0 );
+               mlt_properties_set_timecode( properties, "in", 0.0 );
+               mlt_properties_set_timecode( properties, "out", 36000.0 );
+               mlt_properties_set_timecode( properties, "playtime", 36000.0 );
+               mlt_properties_set_timecode( properties, "length", 36000.0 );
+
+               // Override service get_frame
+               parent->get_frame = producer_get_frame;
+       }
+
+       return 0;
+}
+
+/** Get the parent service object.
+*/
+
+mlt_service mlt_producer_service( mlt_producer this )
+{
+       return &this->parent;
+}
+
+/** Get the producer properties.
+*/
+
+mlt_properties mlt_producer_properties( mlt_producer this )
+{
+       return mlt_service_properties( &this->parent );
+}
+
+/** Seek to a specified time code.
+*/
+
+int mlt_producer_seek( mlt_producer this, mlt_timecode timecode )
+{
+       // Check bounds
+       if ( timecode < 0 )
+               timecode = 0;
+       if ( timecode > mlt_producer_get_playtime( this ) )
+               timecode = mlt_producer_get_playtime( this );
+
+       // Set the position
+       mlt_properties_set_timecode( mlt_producer_properties( this ), "position", timecode );
+
+       // Calculate the absolute frame
+       double frame = ( mlt_producer_get_in( this ) + timecode ) * mlt_producer_get_fps( this );
+       mlt_properties_set_double( mlt_producer_properties( this ), "frame", floor( frame + 0.5 ) );
+
+       return 0;
+}
+
+/** Seek to a specified absolute frame.
+*/
+
+int mlt_producer_seek_frame( mlt_producer this, uint64_t frame )
+{
+       // Calculate the time code
+       double timecode = ( frame / mlt_producer_get_fps( this ) ) - mlt_producer_get_in( this );
+
+       // If timecode is invalid, then seek on time
+       if ( timecode < 0 )
+       {
+               // Seek to the in point
+               mlt_producer_seek( this, 0 );
+       }
+       else if ( timecode > mlt_producer_get_playtime( this ) )
+       {
+               // Seek to the out point
+               mlt_producer_seek( this, mlt_producer_get_playtime( this ) );
+       }
+       else
+       {
+               // Set the position
+               mlt_properties_set_timecode( mlt_producer_properties( this ), "position", timecode );
+
+               // Set the absolute frame
+               mlt_properties_set_double( mlt_producer_properties( this ), "frame", frame );
+       }
+
+       return 0;
+}
+
+/** Get the current time code.
+*/
+
+mlt_timecode mlt_producer_position( mlt_producer this )
+{
+       return mlt_properties_get_timecode( mlt_producer_properties( this ), "position" );
+}
+
+/** Get the current frame.
+*/
+
+uint64_t mlt_producer_frame( mlt_producer this )
+{
+       return mlt_properties_get_double( mlt_producer_properties( this ), "frame" );
+}
+
+/** Set the playing speed.
+*/
+
+int mlt_producer_set_speed( mlt_producer this, double speed )
+{
+       return mlt_properties_set_double( mlt_producer_properties( this ), "speed", speed );
+}
+
+/** Get the playing speed.
+*/
+
+double mlt_producer_get_speed( mlt_producer this )
+{
+       return mlt_properties_get_double( mlt_producer_properties( this ), "speed" );
+}
+
+/** Get the frames per second.
+*/
+
+double mlt_producer_get_fps( mlt_producer this )
+{
+       return mlt_properties_get_double( mlt_producer_properties( this ), "fps" );
+}
+
+/** Set the in and out points.
+*/
+
+int mlt_producer_set_in_and_out( mlt_producer this, mlt_timecode in, mlt_timecode out )
+{
+       // Correct ins and outs if necessary
+       if ( in < 0 )
+               in = 0;
+       if ( in > mlt_producer_get_length( this ) )
+               in = mlt_producer_get_length( this );
+       if ( out < 0 )
+               out = 0;
+       if ( out > mlt_producer_get_length( this ) )
+               out = mlt_producer_get_length( this );
+
+       // Swap ins and outs if wrong
+       if ( out < in )
+       {
+               mlt_timecode t = in;
+               in = out;
+               out = t;
+       }
+
+       // Set the values
+       mlt_properties_set_timecode( mlt_producer_properties( this ), "in", in );
+       mlt_properties_set_timecode( mlt_producer_properties( this ), "out", out );
+       mlt_properties_set_timecode( mlt_producer_properties( this ), "playtime", out - in );
+
+       // Seek to the in point
+       mlt_producer_seek( this, 0 );
+
+       return 0;
+}
+
+/** Get the in point.
+*/
+
+mlt_timecode mlt_producer_get_in( mlt_producer this )
+{
+       return mlt_properties_get_timecode( mlt_producer_properties( this ), "in" );
+}
+
+/** Get the out point.
+*/
+
+mlt_timecode mlt_producer_get_out( mlt_producer this )
+{
+       return mlt_properties_get_timecode( mlt_producer_properties( this ), "out" );
+}
+
+/** Get the total play time.
+*/
+
+mlt_timecode mlt_producer_get_playtime( mlt_producer this )
+{
+       return mlt_properties_get_timecode( mlt_producer_properties( this ), "playtime" );
+}
+
+/** Get the total length of the producer.
+*/
+
+mlt_timecode mlt_producer_get_length( mlt_producer this )
+{
+       return mlt_properties_get_timecode( mlt_producer_properties( this ), "length" );
+}
+
+/** Prepare for next frame.
+*/
+
+void mlt_producer_prepare_next( mlt_producer this )
+{
+       mlt_producer_seek_frame( this, mlt_producer_frame( this ) + mlt_producer_get_speed( this ) );
+}
+
+/** Get a frame.
+*/
+
+static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
+{
+       int result = 1;
+       mlt_producer this = service->child;
+
+       // A properly instatiated producer will have a get_frame method...
+       if ( this->get_frame != NULL )
+       {
+               // Get the frame from the implementation
+               result = this->get_frame( this, frame, index );
+       }
+       else
+       {
+               // Generate a test frame
+               *frame = mlt_frame_init( );
+
+               // Set the timecode
+               result = mlt_frame_set_timecode( *frame, mlt_producer_position( this ) );
+
+               // Calculate the next timecode
+               mlt_producer_prepare_next( this );
+       }
+
+       return 0;
+}
+
+/** Close the producer.
+*/
+
+void mlt_producer_close( mlt_producer this )
+{
+       if ( this->close != NULL )
+               this->close( this );
+       else
+               mlt_service_close( &this->parent );
+}
diff --git a/mlt/src/framework/mlt_producer.h b/mlt/src/framework/mlt_producer.h
new file mode 100644 (file)
index 0000000..a59a82d
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * mlt_producer.h -- abstraction for all producer services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_PRODUCER_H_
+#define _MLT_PRODUCER_H_
+
+#include "mlt_service.h"
+
+/** The interface definition for all producers.
+*/
+
+struct mlt_producer_s
+{
+       // We're implementing service here
+       struct mlt_service_s parent;
+
+       // Public virtual methods
+       int ( *get_frame )( mlt_producer, mlt_frame_ptr, int );
+       void ( *close )( mlt_producer );
+
+       // Private data
+       void *private;
+       void *child;
+};
+
+/** Public final methods
+*/
+
+extern int mlt_producer_init( mlt_producer this, void *child );
+extern mlt_service mlt_producer_service( mlt_producer this );
+extern mlt_properties mlt_producer_properties( mlt_producer this );
+extern int mlt_producer_seek( mlt_producer this, mlt_timecode timecode );
+extern int mlt_producer_seek_frame( mlt_producer this, uint64_t frame );
+extern mlt_timecode mlt_producer_position( mlt_producer this );
+extern uint64_t mlt_producer_frame( mlt_producer this );
+extern int mlt_producer_set_speed( mlt_producer this, double speed );
+extern double mlt_producer_get_speed( mlt_producer this );
+extern double mlt_producer_get_fps( mlt_producer this );
+extern int mlt_producer_set_in_and_out( mlt_producer this, mlt_timecode in, mlt_timecode out );
+extern mlt_timecode mlt_producer_get_in( mlt_producer this );
+extern mlt_timecode mlt_producer_get_out( mlt_producer this );
+extern mlt_timecode mlt_producer_get_playtime( mlt_producer this );
+extern mlt_timecode mlt_producer_get_length( mlt_producer this );
+extern void mlt_producer_prepare_next( mlt_producer this );
+extern void mlt_producer_close( mlt_producer this );
+
+#endif
diff --git a/mlt/src/framework/mlt_properties.c b/mlt/src/framework/mlt_properties.c
new file mode 100644 (file)
index 0000000..233e8ac
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * mlt_properties.c -- base properties class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "mlt_properties.h"
+#include "mlt_property.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* ---------------- // Private Implementation // ---------------- */
+
+/** Private implementation of the property list.
+*/
+
+typedef struct
+{
+       char **name;
+       mlt_property *value;
+       int count;
+       int size;
+}
+property_list;
+
+/** Basic implementation.
+*/
+
+int mlt_properties_init( mlt_properties this, void *child )
+{
+       // NULL all methods
+       memset( this, 0, sizeof( struct mlt_properties_s ) );
+
+       // Assign the child of the object
+       this->child = child;
+
+       // Allocate the private structure
+       this->private = calloc( sizeof( property_list ), 1 );
+
+       return this->private == NULL;
+}
+
+/** Locate a property by name
+*/
+
+static mlt_property mlt_properties_find( mlt_properties this, char *name )
+{
+       mlt_property value = NULL;
+       property_list *list = this->private;
+       int i = 0;
+
+       // Locate the item 
+       for ( i = 0; value == NULL && i < list->count; i ++ )
+               if ( !strcmp( list->name[ i ], name ) )
+                       value = list->value[ i ];
+
+       return value;
+}
+
+/** Add a new property.
+*/
+
+static mlt_property mlt_properties_add( mlt_properties this, char *name )
+{
+       property_list *list = this->private;
+
+       // Check that we have space and resize if necessary
+       if ( list->count == list->size )
+       {
+               list->size += 10;
+               list->name = realloc( list->name, list->size * sizeof( char * ) );
+               list->value = realloc( list->value, list->size * sizeof( mlt_property ) );
+       }
+
+       // Assign name/value pair
+       list->name[ list->count ] = strdup( name );
+       list->value[ list->count ] = mlt_property_init( );
+
+       // Return and increment count accordingly
+       return list->value[ list->count ++ ];
+}
+
+/** Fetch a property by name - this includes add if not found.
+*/
+
+static mlt_property mlt_properties_fetch( mlt_properties this, char *name )
+{
+       // Try to find an existing property first
+       mlt_property property = mlt_properties_find( this, name );
+
+       // If it wasn't found, create one
+       if ( property == NULL )
+               property = mlt_properties_add( this, name );
+
+       // Return the property
+       return property;
+}
+
+/** Set the property.
+*/
+
+int mlt_properties_set( mlt_properties this, char *name, char *value )
+{
+       int error = 1;
+
+       // Fetch the property to work with
+       mlt_property property = mlt_properties_fetch( this, name );
+
+       // Set it if not NULL
+       if ( property != NULL )
+               error = mlt_property_set_string( property, value );
+
+       return error;
+}
+
+/** Get a string value by name.
+*/
+
+char *mlt_properties_get( mlt_properties this, char *name )
+{
+       mlt_property value = mlt_properties_find( this, name );
+       return value == NULL ? NULL : mlt_property_get_string( value );
+}
+
+/** Get a name by index.
+*/
+
+char *mlt_properties_get_name( mlt_properties this, int index )
+{
+       property_list *list = this->private;
+       if ( index >= 0 && index < list->count )
+               return list->name[ index ];
+       return NULL;
+}
+
+/** Get a string value by index.
+*/
+
+char *mlt_properties_get_value( mlt_properties this, int index )
+{
+       property_list *list = this->private;
+       if ( index >= 0 && index < list->count )
+               return mlt_property_get_string( list->value[ index ] );
+       return NULL;
+}
+
+/** Return the number of items in the list.
+*/
+
+int mlt_properties_count( mlt_properties this )
+{
+       property_list *list = this->private;
+       return list->count;
+}
+
+/** Set a value by parsing a name=value string
+*/
+
+int mlt_properties_parse( mlt_properties this, char *namevalue )
+{
+       char *name = strdup( namevalue );
+       char *value = strdup( namevalue );
+       int error = 0;
+
+       if ( strchr( name, '=' ) )
+       {
+               *( strchr( name, '=' ) ) = '\0';
+               strcpy( value, strchr( value, '=' ) + 1 );
+       }
+       else
+       {
+               strcpy( value, "" );
+       }
+
+       error = mlt_properties_set( this, name, value );
+
+       free( name );
+       free( value );
+
+       return error;
+}
+
+/** Get a value associated to the name.
+*/
+
+int mlt_properties_get_int( mlt_properties this, char *name )
+{
+       mlt_property value = mlt_properties_find( this, name );
+       return value == NULL ? 0 : mlt_property_get_int( value );
+}
+
+/** Set a value associated to the name.
+*/
+
+int mlt_properties_set_int( mlt_properties this, char *name, int value )
+{
+       int error = 1;
+
+       // Fetch the property to work with
+       mlt_property property = mlt_properties_fetch( this, name );
+
+       // Set it if not NULL
+       if ( property != NULL )
+               error = mlt_property_set_int( property, value );
+
+       return error;
+}
+
+/** Get a value associated to the name.
+*/
+
+double mlt_properties_get_double( mlt_properties this, char *name )
+{
+       mlt_property value = mlt_properties_find( this, name );
+       return value == NULL ? 0 : mlt_property_get_double( value );
+}
+
+/** Set a value associated to the name.
+*/
+
+int mlt_properties_set_double( mlt_properties this, char *name, double value )
+{
+       int error = 1;
+
+       // Fetch the property to work with
+       mlt_property property = mlt_properties_fetch( this, name );
+
+       // Set it if not NULL
+       if ( property != NULL )
+               error = mlt_property_set_double( property, value );
+
+       return error;
+}
+
+/** Get a value associated to the name.
+*/
+
+mlt_timecode mlt_properties_get_timecode( mlt_properties this, char *name )
+{
+       mlt_property value = mlt_properties_find( this, name );
+       return value == NULL ? 0 : mlt_property_get_timecode( value );
+}
+
+/** Set a value associated to the name.
+*/
+
+int mlt_properties_set_timecode( mlt_properties this, char *name, mlt_timecode value )
+{
+       int error = 1;
+
+       // Fetch the property to work with
+       mlt_property property = mlt_properties_fetch( this, name );
+
+       // Set it if not NULL
+       if ( property != NULL )
+               error = mlt_property_set_timecode( property, value );
+
+       return error;
+}
+
+/** Get a value associated to the name.
+*/
+
+void *mlt_properties_get_data( mlt_properties this, char *name, int *length )
+{
+       mlt_property value = mlt_properties_find( this, name );
+       return value == NULL ? NULL : mlt_property_get_data( value, length );
+}
+
+/** Set a value associated to the name.
+*/
+
+int mlt_properties_set_data( mlt_properties this, char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise )
+{
+       int error = 1;
+
+       // Fetch the property to work with
+       mlt_property property = mlt_properties_fetch( this, name );
+
+       // Set it if not NULL
+       if ( property != NULL )
+               error = mlt_property_set_data( property, value, length, destroy, serialise );
+
+       return error;
+}
+
+/** Close the list.
+*/
+
+void mlt_properties_close( mlt_properties this )
+{
+       property_list *list = this->private;
+       int index = 0;
+
+       // Clean up names and values
+       for ( index = 0; index < list->count; index ++ )
+       {
+               free( list->name[ index ] );
+               mlt_property_close( list->value[ index ] );
+       }
+
+       // Clear up the list
+       free( list->name );
+       free( list->value );
+       free( list );
+}
+
diff --git a/mlt/src/framework/mlt_properties.h b/mlt/src/framework/mlt_properties.h
new file mode 100644 (file)
index 0000000..b64753b
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * mlt_properties.h -- base properties class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_PROPERTIES_H_
+#define _MLT_PROPERTIES_H_
+
+#include "mlt_types.h"
+
+/** The properties base class defines the basic property propagation and
+       handling.
+*/
+
+struct mlt_properties_s
+{
+       void *child;
+       void *private;
+};
+
+/** Public interface.
+*/
+
+extern int mlt_properties_init( mlt_properties, void *child );
+extern int mlt_properties_set( mlt_properties this, char *name, char *value );
+extern int mlt_properties_parse( mlt_properties this, char *namevalue );
+extern char *mlt_properties_get( mlt_properties this, char *name );
+extern char *mlt_properties_get_name( mlt_properties this, int index );
+extern char *mlt_properties_get_value( mlt_properties this, int index );
+extern int mlt_properties_get_int( mlt_properties this, char *name );
+extern int mlt_properties_set_int( mlt_properties this, char *name, int value );
+extern double mlt_properties_get_double( mlt_properties this, char *name );
+extern int mlt_properties_set_double( mlt_properties this, char *name, double value );
+extern mlt_timecode mlt_properties_get_timecode( mlt_properties this, char *name );
+extern int mlt_properties_set_timecode( mlt_properties this, char *name, mlt_timecode value );
+extern int mlt_properties_set_data( mlt_properties this, char *name, void *value, int length, mlt_destructor, mlt_serialiser );
+extern void *mlt_properties_get_data( mlt_properties this, char *name, int *length );
+extern int mlt_properties_count( mlt_properties this );
+extern void mlt_properties_close( mlt_properties this );
+
+#endif
diff --git a/mlt/src/framework/mlt_property.c b/mlt/src/framework/mlt_property.c
new file mode 100644 (file)
index 0000000..021dbc1
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * mlt_property.c -- property class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "mlt_property.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** Construct and uninitialised property.
+*/
+
+mlt_property mlt_property_init( )
+{
+       return calloc( sizeof( struct mlt_property_s ), 1 );
+}
+
+/** Clear a property.
+*/
+
+void mlt_property_clear( mlt_property this )
+{
+       // Special case data handling
+       if ( this->types & mlt_prop_data && this->destructor != NULL )
+               this->destructor( this->data );
+
+       // Special case string handling
+       if ( this->types & mlt_prop_string )
+               free( this->prop_string );
+
+       // We can wipe it now.
+       memset( this, 0, sizeof( struct mlt_property_s ) );
+}
+
+/** Set an int on this property.
+*/
+
+int mlt_property_set_int( mlt_property this, int value )
+{
+       mlt_property_clear( this );
+       this->types = mlt_prop_int;
+       this->prop_int = value;
+       return 0;
+}
+
+/** Set a double on this property.
+*/
+
+int mlt_property_set_double( mlt_property this, double value )
+{
+       mlt_property_clear( this );
+       this->types = mlt_prop_double;
+       this->prop_double = value;
+       return 0;
+}
+
+/** Set a timecode on this property.
+*/
+
+int mlt_property_set_timecode( mlt_property this, mlt_timecode value )
+{
+       mlt_property_clear( this );
+       this->types = mlt_prop_timecode;
+       this->prop_timecode = value;
+       return 0;
+}
+
+/** Set a string on this property.
+*/
+
+int mlt_property_set_string( mlt_property this, char *value )
+{
+       mlt_property_clear( this );
+       this->types = mlt_prop_string;
+       if ( value != NULL )
+               this->prop_string = strdup( value );
+       return this->prop_string != NULL;
+}
+
+/** Set a data on this property.
+*/
+
+int mlt_property_set_data( mlt_property this, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser )
+{
+       mlt_property_clear( this );
+       this->types = mlt_prop_data;
+       this->data = value;
+       this->length = length;
+       this->destructor = destructor;
+       this->serialiser = serialiser;
+       return 0;
+}
+
+/** Get an int from this property.
+*/
+
+int mlt_property_get_int( mlt_property this )
+{
+       if ( this->types & mlt_prop_int )
+               return this->prop_int;
+       else if ( this->types & mlt_prop_double )
+               return ( int )this->prop_double;
+       else if ( this->types & mlt_prop_timecode )
+               return ( int )this->prop_timecode;
+       else if ( this->types & mlt_prop_string )
+               return atoi( this->prop_string );
+       return 0;
+}
+
+/** Get a double from this property.
+*/
+
+double mlt_property_get_double( mlt_property this )
+{
+       if ( this->types & mlt_prop_double )
+               return this->prop_double;
+       else if ( this->types & mlt_prop_int )
+               return ( double )this->prop_int;
+       else if ( this->types & mlt_prop_timecode )
+               return ( double )this->prop_timecode;
+       else if ( this->types & mlt_prop_string )
+               return atof( this->prop_string );
+       return 0;
+}
+
+/** Get a timecode from this property.
+*/
+
+mlt_timecode mlt_property_get_timecode( mlt_property this )
+{
+       if ( this->types & mlt_prop_timecode )
+               return this->prop_timecode;
+       else if ( this->types & mlt_prop_int )
+               return ( mlt_timecode )this->prop_int;
+       else if ( this->types & mlt_prop_double )
+               return ( mlt_timecode )this->prop_double;
+       else if ( this->types & mlt_prop_string )
+               return ( mlt_timecode )atof( this->prop_string );
+       return 0;
+}
+
+/** Get a string from this property.
+*/
+
+char *mlt_property_get_string( mlt_property this )
+{
+       // Construct a string if need be
+       if ( ! ( this->types & mlt_prop_string ) )
+       {
+               if ( this->types & mlt_prop_int )
+               {
+                       this->types |= mlt_prop_string;
+                       this->prop_string = malloc( 32 );
+                       sprintf( this->prop_string, "%d", this->prop_int );
+               }
+               else if ( this->types & mlt_prop_double )
+               {
+                       this->types |= mlt_prop_string;
+                       this->prop_string = malloc( 32 );
+                       sprintf( this->prop_string, "%e", this->prop_double );
+               }
+               else if ( this->types & mlt_prop_timecode )
+               {
+                       this->types |= mlt_prop_string;
+                       this->prop_string = malloc( 32 );
+                       sprintf( this->prop_string, "%e", this->prop_timecode );
+               }
+               else if ( this->types & mlt_prop_data && this->serialiser != NULL )
+               {
+                       this->types |= mlt_prop_string;
+                       this->prop_string = this->serialiser( this->data, this->length );
+               }
+       }
+
+       // Return the string (may be NULL)
+       return this->prop_string;
+}
+
+/** Get a data and associated length.
+*/
+
+void *mlt_property_get_data( mlt_property this, int *length )
+{
+       // Assign length if not NULL
+       if ( length != NULL )
+               *length = this->length;
+
+       // Return the data (note: there is no conversion here)
+       return this->data;
+}
+
+/** Close this property.
+*/
+
+void mlt_property_close( mlt_property this )
+{
+       mlt_property_clear( this );
+       free( this );
+}
+
+
diff --git a/mlt/src/framework/mlt_property.h b/mlt/src/framework/mlt_property.h
new file mode 100644 (file)
index 0000000..8fb209c
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * mlt_property.h -- property class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_PROPERTY_H_
+#define _MLT_PROPERTY_H_
+
+#include "mlt_types.h"
+
+/** Bit pattern for properties.
+*/
+
+typedef enum
+{
+       mlt_prop_none = 0,
+       mlt_prop_int = 1,
+       mlt_prop_string = 2,
+       mlt_prop_timecode = 4,
+       mlt_prop_double = 8,
+       mlt_prop_data = 16
+}
+mlt_property_type;
+
+/** Property structure.
+*/
+
+typedef struct mlt_property_s
+{
+       // Stores a bit pattern of types available for this property
+       mlt_property_type types;
+
+       // Atomic type handling
+       int prop_int;
+       mlt_timecode prop_timecode;
+       double prop_double;
+
+       // String handling
+       char *prop_string;
+
+       // Generic type handling
+       void *data;
+       int length;
+       mlt_destructor destructor;
+       mlt_serialiser serialiser;
+}
+*mlt_property;
+
+/** API
+*/
+
+extern mlt_property mlt_property_init( );
+extern void mlt_property_clear( mlt_property this );
+extern int mlt_property_set_int( mlt_property this, int value );
+extern int mlt_property_set_double( mlt_property this, double value );
+extern int mlt_property_set_timecode( mlt_property this, mlt_timecode value );
+extern int mlt_property_set_string( mlt_property this, char *value );
+extern int mlt_property_set_data( mlt_property this, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser );
+extern int mlt_property_get_int( mlt_property this );
+extern double mlt_property_get_double( mlt_property this );
+extern mlt_timecode mlt_property_get_timecode( mlt_property this );
+extern char *mlt_property_get_string( mlt_property this );
+extern void *mlt_property_get_data( mlt_property this, int *length );
+extern void mlt_property_close( mlt_property this );
+
+#endif
+
diff --git a/mlt/src/framework/mlt_repository.c b/mlt/src/framework/mlt_repository.c
new file mode 100644 (file)
index 0000000..9c41bf9
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * repository.c -- provides a map between service and shared objects
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "mlt_repository.h"
+#include <stdlib.h>
+
+struct mlt_repository_s
+{
+};
+
+mlt_repository mlt_repository_init( char *file, char *symbol )
+{
+       return NULL;
+}
+
+void *mlt_repository_fetch( mlt_repository this, char *service, void *input )
+{
+       return NULL;
+}
+
+void mlt_repository_close( mlt_repository this )
+{
+}
+
+
diff --git a/mlt/src/framework/mlt_repository.h b/mlt/src/framework/mlt_repository.h
new file mode 100644 (file)
index 0000000..afab1cc
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * repository.h -- provides a map between service and shared objects
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_REPOSITORY_H_
+#define _MLT_REPOSITORY_H_
+
+/** Repository structure forward reference.
+*/
+
+typedef struct mlt_repository_s *mlt_repository;
+
+/** Public functions.
+*/
+
+extern mlt_repository mlt_repository_init( char *file, char *symbol );
+extern void *mlt_repository_fetch( mlt_repository this, char *service, void *input );
+extern void mlt_repository_close( mlt_repository this );
+
+#endif
+
diff --git a/mlt/src/framework/mlt_service.c b/mlt/src/framework/mlt_service.c
new file mode 100644 (file)
index 0000000..8e626d4
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * mlt_service.c -- interface for all service classes
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "mlt_service.h"
+#include "mlt_frame.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** IMPORTANT NOTES
+
+       The base service implements a null frame producing service - as such,
+       it is functional without extension and will produce test cards frames 
+       and PAL sized audio frames.
+
+       PLEASE DO NOT CHANGE THIS BEHAVIOUR!!! OVERRIDE THE METHODS THAT 
+       CONTROL THIS IN EXTENDING CLASSES.
+*/
+
+/** Private service definition.
+*/
+
+typedef struct
+{
+       int size;
+       int count;
+       mlt_service *in;
+       mlt_service out;
+}
+mlt_service_base;
+
+/** Friends?
+*/
+
+static void mlt_service_disconnect( mlt_service this );
+static void mlt_service_connect( mlt_service this, mlt_service that );
+static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
+
+/** Constructor
+*/
+
+int mlt_service_init( mlt_service this, void *child )
+{
+       // Initialise everything to NULL
+       memset( this, 0, sizeof( struct mlt_service_s ) );
+
+       // Assign the child
+       this->child = child;
+
+       // Generate private space
+       this->private = calloc( sizeof( mlt_service_base ), 1 );
+
+       // Associate the methods
+       this->get_frame = service_get_frame;
+       
+       // Initialise the properties
+       return mlt_properties_init( &this->parent, this );
+}
+
+/** Return the properties object.
+*/
+
+mlt_properties mlt_service_properties( mlt_service this )
+{
+       return &this->parent;
+}
+
+/** Connect a producer service.
+       Returns: > 0 warning, == 0 success, < 0 serious error
+                        1 = this service does not accept input
+                        2 = the producer is invalid
+                        3 = the producer is already registered with this consumer
+*/
+
+int mlt_service_connect_producer( mlt_service this, mlt_service producer, int index )
+{
+       int i = 0;
+
+       // Get the service base
+       mlt_service_base *base = this->private;
+
+       // Does this service accept input?
+       if ( mlt_service_accepts_input( this ) == 0 )
+               return 1;
+
+       // Does the producer service accept output connections?
+       if ( mlt_service_accepts_output( producer ) == 0 )
+               return 2;
+
+       // Check if the producer is already registered with this service
+       for ( i = 0; i < base->count; i ++ )
+               if ( base->in[ i ] == producer )
+                       return 3;
+
+       // Allocate space
+       if ( index >= base->size )
+       {
+               int new_size = base->size + index + 10;
+               base->in = realloc( base->in, new_size * sizeof( mlt_service ) );
+               if ( base->in != NULL )
+               {
+                       for ( i = base->size; i < new_size; i ++ )
+                               base->in[ i ] = NULL;
+                       base->size = new_size;
+               }
+       }
+
+       // If we have space, assign the input
+       if ( base->in != NULL && index >= 0 && index < base->size )
+       {
+               // Now we disconnect the producer service from its consumer
+               mlt_service_disconnect( producer );
+               
+               // Add the service to index specified
+               base->in[ index ] = producer;
+               
+               // Determine the number of active tracks
+               if ( index >= base->count )
+                       base->count = index + 1;
+
+               // Now we connect the producer to its connected consumer
+               mlt_service_connect( producer, this );
+
+               // Inform caller that all went well
+               return 0;
+       }
+       else
+       {
+               return -1;
+       }
+}
+
+/** Disconnect this service from its consumer.
+*/
+
+void mlt_service_disconnect( mlt_service this )
+{
+       // Get the service base
+       mlt_service_base *base = this->private;
+
+       // There's a bit more required here...
+       base->out = NULL;
+}
+
+/** Associate this service to the its consumer.
+*/
+
+void mlt_service_connect( mlt_service this, mlt_service that )
+{
+       // Get the service base
+       mlt_service_base *base = this->private;
+
+       // There's a bit more required here...
+       base->out = that;
+}
+
+/** Get the service state.
+*/
+
+mlt_service_state mlt_service_get_state( mlt_service this )
+{
+       mlt_service_state state = mlt_state_unknown;
+       if ( mlt_service_has_input( this ) )
+               state |= mlt_state_providing;
+       if ( mlt_service_has_output( this ) )
+               state |= mlt_state_connected;
+       if ( state != ( mlt_state_providing | mlt_state_connected ) )
+               state |= mlt_state_dormant;
+       return state;
+}
+
+/** Get the maximum number of inputs accepted.
+       Returns: -1 for many, 0 for none or n for fixed.
+*/
+
+int mlt_service_accepts_input( mlt_service this )
+{
+       if ( this->accepts_input == NULL )
+               return -1;
+       else
+               return this->accepts_input( this );
+}
+
+/** Get the maximum number of outputs accepted.
+*/
+
+int mlt_service_accepts_output( mlt_service this )
+{
+       if ( this->accepts_output == NULL )
+               return 1;
+       else
+               return this->accepts_output( this );
+}
+
+/** Determines if this service has input
+*/
+
+int mlt_service_has_input( mlt_service this )
+{
+       if ( this->has_input == NULL )
+               return 1;
+       else
+               return this->has_input( this );
+}
+
+/** Determine if this service has output
+*/
+
+int mlt_service_has_output( mlt_service this )
+{
+       mlt_service_base *base = this->private;
+       if ( this->has_output == NULL )
+               return base->out != NULL;
+       else
+               return this->has_output( this );
+}
+
+/** Check if the service is active.
+*/
+
+int mlt_service_is_active( mlt_service this )
+{
+       return !( mlt_service_get_state( this ) & mlt_state_dormant );
+}
+
+/** Obtain a frame to pass on.
+*/
+
+static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
+{
+       mlt_service_base *base = this->private;
+       if ( index < base->count )
+       {
+               mlt_service producer = base->in[ index ];
+               if ( producer != NULL )
+                       return mlt_service_get_frame( producer, frame, index );
+       }
+       *frame = mlt_frame_init( );
+       return 0;
+}
+
+int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
+{
+       return this->get_frame( this, frame, index );
+}
+
+/** Close the service.
+*/
+
+void mlt_service_close( mlt_service this )
+{
+       mlt_service_base *base = this->private;
+       free( base->in );
+       free( base );
+       mlt_properties_close( &this->parent );
+}
+
diff --git a/mlt/src/framework/mlt_service.h b/mlt/src/framework/mlt_service.h
new file mode 100644 (file)
index 0000000..88b91b5
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * mlt_service.h -- interface for all service classes
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_SERVICE_H_
+#define _MLT_SERVICE_H_
+
+#include "mlt_properties.h"
+
+/** State of a service.
+
+    Note that a service may be dormant even though it's fully connected,
+       providing or consuming.
+*/
+
+typedef enum
+{
+       mlt_state_unknown   = 0,
+       mlt_state_dormant   = 1,
+       mlt_state_connected = 2,
+       mlt_state_providing = 4,
+       mlt_state_consuming = 8
+}
+mlt_service_state;
+
+/** The interface definition for all services.
+*/
+
+struct mlt_service_s
+{
+       // We're extending properties here
+       struct mlt_properties_s parent;
+
+       // Protected virtual
+       int ( *accepts_input )( mlt_service this );
+       int ( *accepts_output )( mlt_service this );
+       int ( *has_input )( mlt_service this );
+       int ( *has_output )( mlt_service this );
+       int ( *get_frame )( mlt_service this, mlt_frame_ptr frame, int index );
+
+       // Private data
+       void *private;
+       void *child;
+};
+
+/** The public API.
+*/
+
+extern int mlt_service_init( mlt_service this, void *child );
+extern mlt_properties mlt_service_properties( mlt_service this );
+extern int mlt_service_connect_producer( mlt_service this, mlt_service producer, int index );
+extern mlt_service_state mlt_service_get_state( mlt_service this );
+extern void mlt_service_close( mlt_service this );
+
+extern int mlt_service_accepts_input( mlt_service this );
+extern int mlt_service_accepts_output( mlt_service this );
+extern int mlt_service_has_input( mlt_service this );
+extern int mlt_service_has_output( mlt_service this );
+extern int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
+extern int mlt_service_is_active( mlt_service this );
+
+#endif
+
diff --git a/mlt/src/framework/mlt_tractor.c b/mlt/src/framework/mlt_tractor.c
new file mode 100644 (file)
index 0000000..f4b77c4
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * mlt_tractor.c -- tractor service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "mlt_tractor.h"
+#include "mlt_frame.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/** Private structure.
+*/
+
+struct mlt_tractor_s
+{
+       struct mlt_service_s parent;
+       mlt_service producer;
+};
+
+/** Forward references to static methods.
+*/
+
+static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int track );
+
+/** Constructor for the tractor.
+
+       TODO: thread this service...
+*/
+
+mlt_tractor mlt_tractor_init( )
+{
+       mlt_tractor this = calloc( sizeof( struct mlt_tractor_s ), 1 );
+       if ( this != NULL )
+       {
+               mlt_service service = &this->parent;
+               if ( mlt_service_init( service, this ) == 0 )
+               {
+                       service->get_frame = service_get_frame;
+               }
+               else
+               {
+                       free( this );
+                       this = NULL;
+               }
+       }
+       return this;
+}
+
+/** Get the service object associated to the tractor.
+*/
+
+mlt_service mlt_tractor_service( mlt_tractor this )
+{
+       return &this->parent;
+}
+
+/** Connect the tractor.
+*/
+
+int mlt_tractor_connect( mlt_tractor this, mlt_service producer )
+{
+       int ret = mlt_service_connect_producer( &this->parent, producer, 0 );
+
+       if ( ret == 0 )
+       {
+               // This is the producer we're going to connect to
+               this->producer = producer;
+       }
+
+       return ret;
+}
+
+/** Get the next frame.
+
+       TODO: This should be reading a pump being populated by the thread...
+*/
+
+static int service_get_frame( mlt_service parent, mlt_frame_ptr frame, int track )
+{
+       mlt_tractor this = parent->child;
+
+       // We only respond to the first track requests
+       if ( track == 0 && this->producer != NULL )
+       {
+               int i = 0;
+               int looking = 1;
+               int done = 0;
+               mlt_frame temp;
+
+               // Loop through each of the tracks we're harvesting
+               for ( i = 0; !done; i ++ )
+               {
+                       // Get a frame from the producer
+                       mlt_service_get_frame( this->producer, &temp, i );
+
+                       // Check for last track
+                       done = mlt_properties_get_int( mlt_frame_properties( temp ), "last_track" );
+
+                       // Handle the frame
+                       if ( done && looking )
+                       {
+                               // Use this as output if we don't have one already
+                               *frame = temp;
+                       }
+                       else if ( !mlt_frame_is_test_card( temp ) && looking )
+                       {
+                               // This is the one we want and we can stop looking
+                               *frame = temp;
+                               looking = 0;
+                       }
+                       else
+                       {
+                               // We discard all other frames
+                               mlt_frame_close( temp );
+                       }
+               }
+
+               // Indicate our found status
+               return 0;
+       }
+       else
+       {
+               // Generate a test card
+               *frame = mlt_frame_init( );
+               return 0;
+       }
+}
+
+/** Close the tractor.
+*/
+
+void mlt_tractor_close( mlt_tractor this )
+{
+       mlt_service_close( &this->parent );
+       free( this );
+}
+
diff --git a/mlt/src/framework/mlt_tractor.h b/mlt/src/framework/mlt_tractor.h
new file mode 100644 (file)
index 0000000..28a6071
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * mlt_tractor.h -- tractor service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_TRACTOR_H_
+#define _MLT_TRACTOR_H_
+
+#include "mlt_producer.h"
+
+extern mlt_tractor mlt_tractor_init( );
+extern mlt_service mlt_tractor_service( mlt_tractor this );
+extern int mlt_tractor_connect( mlt_tractor this, mlt_service service );
+extern void mlt_tractor_close( mlt_tractor this );
+
+#endif
diff --git a/mlt/src/framework/mlt_transition.c b/mlt/src/framework/mlt_transition.c
new file mode 100644 (file)
index 0000000..dd4f2f6
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * mlt_transition.c -- abstraction for all transition services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "mlt_transition.h"
+#include "mlt_frame.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** Forward references.
+*/
+
+static int transition_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
+
+/** Constructor.
+*/
+
+int mlt_transition_init( mlt_transition this, void *child )
+{
+       mlt_service service = &this->parent;
+       memset( this, 0, sizeof( struct mlt_transition_s ) );
+       this->child = child;
+       if ( mlt_service_init( service, this ) == 0 )
+       {
+               service->get_frame = transition_get_frame;
+               return 0;
+       }
+       return 1;
+}
+
+/** Get the service associated to the transition.
+*/
+
+mlt_service mlt_transition_service( mlt_transition this )
+{
+       return &this->parent;
+}
+
+/** Connect this transition with a producers a and b tracks.
+*/
+
+int mlt_transition_connect( mlt_transition this, mlt_service producer, int a_track, int b_track )
+{
+       int ret = mlt_service_connect_producer( &this->parent, producer, a_track );
+       if ( ret == 0 )
+       {
+               this->producer = producer;
+               this->a_track = a_track;
+               this->b_track = b_track;
+               this->in = 0;
+               this->out = 0;
+       }
+       return ret;
+}
+
+/** Set the in and out points.
+*/
+
+void mlt_transition_set_in_and_out( mlt_transition this, mlt_timecode in, mlt_timecode out )
+{
+       this->in = in;
+       this->out = out;
+}
+
+/** Get the index of the a track.
+*/
+
+int mlt_transition_get_a_track( mlt_transition this )
+{
+       return this->a_track;
+}
+
+/** Get the index of the b track.
+*/
+
+int mlt_transition_get_b_track( mlt_transition this )
+{
+       return this->b_track;
+}
+
+/** Get the in point.
+*/
+
+mlt_timecode mlt_transition_get_in( mlt_transition this )
+{
+       return this->in;
+}
+
+/** Get the out point.
+*/
+
+mlt_timecode mlt_transition_get_out( mlt_transition this )
+{
+       return this->out;
+}
+
+/** Process the frame.
+*/
+
+static mlt_frame transition_process( mlt_transition this, mlt_frame a_frame, mlt_frame b_frame )
+{
+       if ( this->process == NULL )
+       {
+               if ( !mlt_frame_is_test_card( a_frame ) )
+               {
+                       mlt_frame_close( b_frame );
+                       return a_frame;
+               }
+               else
+               {
+                       mlt_frame_close( a_frame );
+                       return b_frame;
+               }
+       }
+       else
+       {
+               return this->process( this, a_frame, b_frame );
+       }
+}
+
+/** Get a frame from this filter.
+
+       The logic is complex here. A transition is applied to frames on the a and b tracks
+       specified in the connect method above. Since all frames are obtained via this 
+       method for all tracks, we have to take special care that we only obtain the a and
+       b frames once - we do this on the first call to get a frame from either a or b.
+       
+       After that, we have 3 cases to resolve:
+       
+       1)      if the track is the a_track and we're in the time zone, then we need to call the
+               process method to do the effect on the frame (we assign NULL to the a_frame and
+               b_frames here) otherwise, we pass on the a_frame unmolested;
+       2)      if the track is the b_track and we're the in the time zone OR the b_frame is NULL,
+               then we generate a test card frame, otherwise we pass on the b frame unmolested;
+       3)      For all other tracks, we get the frames on demand.
+*/
+
+static int transition_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
+{
+       mlt_transition this = service->child;
+
+       // Fetch a and b frames together...
+       if ( ( index == this->a_track || index == this->b_track ) &&
+                ( this->a_frame == NULL && this->b_frame == NULL ) )
+       {
+               mlt_service_get_frame( this->producer, &this->a_frame, this->a_track );
+               mlt_service_get_frame( this->producer, &this->b_frame, this->b_track );
+       }
+       
+       // Special case track processing
+       if ( index == this->a_track )
+       {
+               // Determine if we're in the right time zone
+               mlt_timecode timecode = mlt_frame_get_timecode( this->a_frame );
+               if ( timecode >= this->in && timecode < this->out )
+               {
+                       // Process the transition
+                       *frame = transition_process( this, this->a_frame, this->b_frame );
+                       
+                       // Important - NULL both frames now so that we know they're done...
+                       this->a_frame = NULL;
+                       this->b_frame = NULL;
+               }
+               else
+               {
+                       // Pass on the 'a frame' and remember that we've done it
+                       *frame = this->a_frame;
+                       this->a_frame = NULL;
+               }                       
+               return 0;
+       }
+       if ( index == this->b_track )
+       {
+               if ( this->b_frame == NULL )
+               {
+                       // We're *probably* in the zone and the a frame has been requested
+                       *frame = mlt_frame_init( );
+               }
+               else
+               {
+                       mlt_timecode timecode = mlt_frame_get_timecode( this->b_frame );
+                       if ( timecode >= this->in && timecode < this->out )
+                       {
+                               // We're in the zone, but the 'a frame' has not been requested yet
+                               *frame = mlt_frame_init( );
+                       }
+                       else
+                       {
+                               // We're out of the zone, pass on b and remember that we've done it
+                               *frame = this->b_frame;
+                               this->b_frame = NULL;
+                       }
+               }
+               return 0;
+       }
+       else
+       {
+               // Pass through
+               return mlt_service_get_frame( this->producer, frame, index );
+       }
+}
+
+/** Close the transition.
+*/
+
+void mlt_transitition_close( mlt_transition this )
+{
+       if ( this->close != NULL )
+               this->close( this );
+       else
+               mlt_service_close( &this->parent );
+}
diff --git a/mlt/src/framework/mlt_transition.h b/mlt/src/framework/mlt_transition.h
new file mode 100644 (file)
index 0000000..397483f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * mlt_transition.h -- abstraction for all transition services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_TRANSITION_H_
+#define _MLT_TRANSITION_H_
+
+#include "mlt_service.h"
+
+/** The interface definition for all transitions.
+*/
+
+struct mlt_transition_s
+{
+       // We're implementing service here
+       struct mlt_service_s parent;
+
+       // public virtual
+       void ( *close )( mlt_transition );
+
+       // protected transition method
+       mlt_frame ( *process )( mlt_transition, mlt_frame, mlt_frame );
+
+       // Protected
+       void *child;
+       
+       // track and in/out points
+       mlt_service producer;
+       int a_track;
+       int b_track;
+       mlt_timecode in;
+       mlt_timecode out;
+       
+       // Private
+       mlt_frame a_frame;
+       mlt_frame b_frame;
+};
+
+/** Public final methods
+*/
+
+extern int mlt_transition_init( mlt_transition this, void *child );
+extern mlt_service mlt_transition_service( mlt_transition this );
+extern int mlt_transition_connect( mlt_transition this, mlt_service producer, int a_track, int b_track );
+extern void mlt_transition_set_in_and_out( mlt_transition this, mlt_timecode in, mlt_timecode out );
+extern int mlt_transition_get_a_track( mlt_transition this );
+extern int mlt_transition_get_b_track( mlt_transition this );
+extern mlt_timecode mlt_transition_get_in( mlt_transition this );
+extern mlt_timecode mlt_transition_get_out( mlt_transition this );
+extern void mlt_transitition_close( mlt_transition this );
+
+#endif
diff --git a/mlt/src/framework/mlt_types.h b/mlt/src/framework/mlt_types.h
new file mode 100644 (file)
index 0000000..aa97463
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * mlt_types.h -- provides forward definitions of all public types
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_TYPES_H_
+#define _MLT_TYPES_H_
+
+#include <stdint.h>
+
+typedef double mlt_timecode;
+typedef struct mlt_frame_s *mlt_frame, **mlt_frame_ptr;
+typedef struct mlt_properties_s *mlt_properties;
+typedef struct mlt_service_s *mlt_service;
+typedef struct mlt_producer_s *mlt_producer;
+typedef struct mlt_manager_s *mlt_manager;
+typedef struct mlt_playlist_s *mlt_playlist;
+typedef struct mlt_multitrack_s *mlt_multitrack;
+typedef struct mlt_filter_s *mlt_filter;
+typedef struct mlt_transition_s *mlt_transition;
+typedef struct mlt_consumer_s *mlt_consumer;
+typedef struct mlt_tractor_s *mlt_tractor;
+
+typedef void ( *mlt_destructor )( void * );
+typedef char *( *mlt_serialiser )( void *, int length );
+
+
+#endif
diff --git a/mlt/src/miracle/configure b/mlt/src/miracle/configure
new file mode 100755 (executable)
index 0000000..1a24852
--- /dev/null
@@ -0,0 +1 @@
+#!/bin/sh
diff --git a/mlt/src/miracle/miracle.c b/mlt/src/miracle/miracle.c
new file mode 100644 (file)
index 0000000..47a645a
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * dv1394d.c -- A DV over IEEE 1394 TCP Server
+ *
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Authors:
+ *     Dan Dennedy <dan@dennedy.org>
+ *     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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+
+/* Application header files */
+#include "dvserver.h"
+#include "log.h"
+
+/** Our dv server.
+*/
+
+static dv_server server = NULL;
+
+/** atexit shutdown handler for the server.
+*/
+
+static void main_cleanup( )
+{
+       dv_server_shutdown( server );
+}
+
+/** Report usage and exit.
+*/
+
+void usage( char *app )
+{
+       fprintf( stderr, "Usage: %s [-test] [-port NNNN]\n", app );
+       exit( 0 );
+}
+
+/** The main function.
+*/
+
+int main( int argc, char **argv )
+{
+       int error = 0;
+       int index = 0;
+       int background = 1;
+       struct timespec tm = { 5, 0 };
+
+       server = dv_server_init( argv[ 0 ] );
+
+       for ( index = 1; index < argc; index ++ )
+       {
+               if ( !strcmp( argv[ index ], "-port" ) )
+                       dv_server_set_port( server, atoi( argv[ ++ index ] ) );
+               else if ( !strcmp( argv[ index ], "-proxy" ) )
+                       dv_server_set_proxy( server, argv[ ++ index ] );
+               else if ( !strcmp( argv[ index ], "-test" ) )
+                       background = 0;
+               else
+                       usage( argv[ 0 ] );
+       }
+
+       /* Optionally detatch ourselves from the controlling tty */
+
+       if ( background )
+       {
+               if ( fork() )
+                       return 0;
+               setsid();
+               dv1394d_log_init( log_syslog, LOG_INFO );
+       }
+       else
+       {
+               dv1394d_log_init( log_stderr, LOG_INFO );
+       }
+
+       atexit( main_cleanup );
+
+       /* Execute the server */
+       error = dv_server_execute( server );
+
+       /* We need to wait until we're exited.. */
+       while ( !server->shutdown )
+               nanosleep( &tm, NULL );
+
+       return error;
+}
diff --git a/mlt/src/miracle/miracle_commands.c b/mlt/src/miracle/miracle_commands.c
new file mode 100644 (file)
index 0000000..8a492d1
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * global_commands.c
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <pthread.h>
+
+#include "dvunit.h"
+#include "global_commands.h"
+#include "raw1394util.h"
+#include <libavc1394/rom1394.h>
+#include "log.h"
+
+static dv_unit g_units[MAX_UNITS];
+
+
+/** Return the dv_unit given a numeric index.
+*/
+
+dv_unit dv1394d_get_unit( int n )
+{
+       if (n < MAX_UNITS)
+               return g_units[n];
+       else
+               return NULL;
+}
+
+/** Destroy the dv_unit given its numeric index.
+*/
+
+void dv1394d_delete_unit( int n )
+{
+       if (n < MAX_UNITS)
+       {
+               dv_unit unit = dv1394d_get_unit(n);
+               if (unit != NULL)
+               {
+                       dv_unit_close( unit );
+                       g_units[ n ] = NULL;
+                       dv1394d_log( LOG_NOTICE, "Deleted unit U%d.", n ); 
+               }
+       }
+}
+
+/** Destroy all allocated units on the server.
+*/
+
+void dv1394d_delete_all_units( void )
+{
+       int i;
+       for (i = 0; i < MAX_UNITS; i++)
+               if ( dv1394d_get_unit(i) != NULL )
+               {
+                       dv_unit_close( dv1394d_get_unit(i) );
+                       dv1394d_log( LOG_NOTICE, "Deleted unit U%d.", i ); 
+               }
+}
+
+/** Add a DV virtual vtr to the server.
+*/
+response_codes dv1394d_add_unit( command_argument cmd_arg )
+{
+       int i;
+       int channel = -1;
+       char *guid_str = (char*) cmd_arg->argument;
+       octlet_t guid;
+       uint32_t guid_hi;
+       uint32_t guid_lo;
+       
+       sscanf( guid_str, "%08x%08x", &guid_hi, &guid_lo );
+       guid = (octlet_t)guid_hi << 32 | (octlet_t) guid_lo;
+
+       if ( dv_tokeniser_count( cmd_arg->tokeniser ) == 3 )
+               channel = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 2 ) );
+
+       /* make sure unit does not already exit */
+       for (i = 0; i < MAX_UNITS; i++)
+       {
+               if (g_units[i] != NULL)
+                       if ( dv_unit_get_guid( g_units[i] ) == guid )
+                       {
+                               dv_response_printf( cmd_arg->response, 1024, "a unit already exists for that node\n\n" );
+                               return RESPONSE_ERROR;
+                       }
+       }
+       
+       for (i = 0; i < MAX_UNITS; i++)
+       {
+               if (g_units[i] == NULL)
+               {
+               
+                       g_units[ i ] = dv_unit_init( guid, channel );
+                       if ( g_units[ i ] == NULL )
+                       {
+                               dv_response_printf( cmd_arg->response, 1024, "failed to allocate unit\n" );
+                               return RESPONSE_ERROR;
+                       }
+                       g_units[ i ]->unit = i;
+                       dv_unit_set_notifier( g_units[ i ], dv_parser_get_notifier( cmd_arg->parser ), cmd_arg->root_dir );
+
+                       dv1394d_log( LOG_NOTICE, "added unit %d to send to node %d over channel %d", 
+                               i, dv_unit_get_nodeid( g_units[i] ), dv_unit_get_channel( g_units[i] ) );
+                       dv_response_printf( cmd_arg->response, 10, "U%1d\n\n", i );
+                       return RESPONSE_SUCCESS_N;
+               }
+       }
+       
+       dv_response_printf( cmd_arg->response, 1024, "no more units can be created\n\n" );
+
+       return RESPONSE_ERROR;
+}
+
+
+/** List all AV/C nodes on the bus.
+*/
+response_codes dv1394d_list_nodes( command_argument cmd_arg )
+{
+       response_codes error = RESPONSE_SUCCESS_N;
+       raw1394handle_t handle;
+       int i, j;
+       char line[1024];
+       octlet_t guid;
+       rom1394_directory dir;
+
+       for ( j = 0; j < raw1394_get_num_ports(); j++ )
+       {
+               handle = raw1394_open(j);
+               for ( i = 0; i < raw1394_get_nodecount(handle); ++i )
+               {
+                       rom1394_get_directory( handle, i, &dir);
+                       if ( (rom1394_get_node_type(&dir) == ROM1394_NODE_TYPE_AVC) )
+                       {
+                               guid = rom1394_get_guid(handle, i);
+                               if (dir.label != NULL)
+                               {
+                                       snprintf( line, 1023, "%02d %08x%08x \"%s\"\n", i, 
+                                               (quadlet_t) (guid>>32), (quadlet_t) (guid & 0xffffffff), dir.label );
+                               } else {
+                                       snprintf( line, 1023, "%02d %08x%08x \"Unlabeled Node %d\"\n", i, 
+                                               (quadlet_t) (guid>>32), (quadlet_t) (guid & 0xffffffff), i );
+                               }
+                               dv_response_write( cmd_arg->response, line, strlen(line) );
+                               rom1394_free_directory( &dir);
+                       }
+               }
+               raw1394_close( handle );
+       }
+       dv_response_write( cmd_arg->response, "\n", 1 );
+       return error;
+}
+
+
+/** List units already added to server.
+*/
+response_codes dv1394d_list_units( command_argument cmd_arg )
+{
+       response_codes error = RESPONSE_SUCCESS_N;
+       char line[1024];
+       int i;
+       
+       for (i = 0; i < MAX_UNITS; i++)
+       {
+               if (dv1394d_get_unit(i) != NULL)
+               {
+                       snprintf( line, 1023, "U%d %02d %08x%08x %d\n", i, dv_unit_get_nodeid(g_units[i]),
+                       (quadlet_t) (dv_unit_get_guid(g_units[i]) >> 32), 
+                       (quadlet_t) (dv_unit_get_guid(g_units[i]) & 0xffffffff),
+                       !dv_unit_is_offline( g_units[i] ) );
+                       dv_response_write( cmd_arg->response, line, strlen(line) );
+               }
+       }
+       dv_response_write( cmd_arg->response, "\n", 1 );
+
+       return error;
+}
+
+static int
+filter_files( const struct dirent *de )
+{
+       if ( de->d_name[ 0 ] != '.' )
+               return 1;
+       else
+               return 0;
+}
+
+/** List clips in a directory.
+*/
+response_codes dv1394d_list_clips( command_argument cmd_arg )
+{
+       response_codes error = RESPONSE_BAD_FILE;
+       const char *dir_name = (const char*) cmd_arg->argument;
+       DIR *dir;
+       char fullname[1024];
+       struct dirent **de = NULL;
+       int i, n;
+       
+       snprintf( fullname, 1023, "%s%s", cmd_arg->root_dir, dir_name );
+       dir = opendir( fullname );
+       if (dir != NULL)
+       {
+               struct stat info;
+               error = RESPONSE_SUCCESS_N;
+               n = scandir( fullname, &de, filter_files, alphasort );
+               for (i = 0; i < n; i++ )
+               {
+                       snprintf( fullname, 1023, "%s%s/%s", cmd_arg->root_dir, dir_name, de[i]->d_name );
+                       if ( stat( fullname, &info ) == 0 && S_ISDIR( info.st_mode ) )
+                               dv_response_printf( cmd_arg->response, 1024, "\"%s/\"\n", de[i]->d_name );
+               }
+               for (i = 0; i < n; i++ )
+               {
+                       snprintf( fullname, 1023, "%s%s/%s", cmd_arg->root_dir, dir_name, de[i]->d_name );
+                       if ( lstat( fullname, &info ) == 0 && 
+                                ( S_ISREG( info.st_mode ) || ( strstr( fullname, ".clip" ) && info.st_mode | S_IXUSR ) ) )
+                               dv_response_printf( cmd_arg->response, 1024, "\"%s\" %llu\n", de[i]->d_name, (unsigned long long) info.st_size );
+                       free( de[ i ] );
+               }
+               free( de );
+               closedir( dir );
+               dv_response_write( cmd_arg->response, "\n", 1 );
+       }
+
+       return error;
+}
+
+/** Set a server configuration property.
+*/
+
+response_codes dv1394d_set_global_property( command_argument cmd_arg )
+{
+       char *key = (char*) cmd_arg->argument;
+       char *value = NULL;
+
+       value = strchr( key, '=' );
+       if (value == NULL)
+               return RESPONSE_OUT_OF_RANGE;
+       *value = 0;
+       value++;
+       dv1394d_log( LOG_DEBUG, "SET %s = %s", key, value );
+
+       if ( strncasecmp( key, "root", 1024) == 0 )
+       {
+               int len = strlen(value);
+               int i;
+               
+               /* stop all units and unload clips */
+               for (i = 0; i < MAX_UNITS; i++)
+               {
+                       if (g_units[i] != NULL)
+                               dv_unit_terminate( g_units[i] );
+               }
+
+               /* set the property */
+               strncpy( cmd_arg->root_dir, value, 1023 );
+
+               /* add a trailing slash if needed */
+               if ( cmd_arg->root_dir[ len - 1 ] != '/')
+               {
+                       cmd_arg->root_dir[ len ] = '/';
+                       cmd_arg->root_dir[ len + 1 ] = '\0';
+               }
+       }
+       else
+               return RESPONSE_OUT_OF_RANGE;
+       
+       return RESPONSE_SUCCESS;
+}
+
+/** Get a server configuration property.
+*/
+
+response_codes dv1394d_get_global_property( command_argument cmd_arg )
+{
+       char *key = (char*) cmd_arg->argument;
+
+       if ( strncasecmp( key, "root", 1024) == 0 )
+       {
+               dv_response_write( cmd_arg->response, cmd_arg->root_dir, strlen(cmd_arg->root_dir) );
+               return RESPONSE_SUCCESS_1;
+       }
+       else
+               return RESPONSE_OUT_OF_RANGE;
+       
+       return RESPONSE_SUCCESS;
+}
+
+/** IEEE 1394 Bus Reset handler 
+
+    This is included here for now due to all the unit management involved.
+*/
+
+static int reset_handler( raw1394handle_t h, unsigned int generation )
+{
+       int i, j, count, retry = 3;
+       int port = (int) raw1394_get_userdata( h );
+       
+       raw1394_update_generation( h, generation );
+       dv1394d_log( LOG_NOTICE, "bus reset on port %d", port );
+
+       while ( retry-- > 0 ) 
+       {
+               raw1394handle_t handle = raw1394_open( port );
+               count = raw1394_get_nodecount( handle );
+               
+               if ( count > 0 )
+               {
+                       dv1394d_log( LOG_DEBUG, "bus reset, checking units" );
+                       
+                       /* suspend all units on this port */
+                       for ( j = MAX_UNITS; j > 0; j-- )
+                       {
+                               if ( g_units[ j-1 ] != NULL && dv_unit_get_port( g_units[ j-1 ] ) == port )
+                                       dv_unit_suspend( g_units[ j-1 ] );
+                       }
+                       dv1394d_log( LOG_DEBUG, "All units are now stopped" );
+                       
+                       /* restore units with known guid, take others offline */
+                       for ( j = 0; j < MAX_UNITS; j++ )
+                       {
+                               if ( g_units[j] != NULL && 
+                                       ( dv_unit_get_port( g_units[ j ] ) == port || dv_unit_get_port( g_units[ j ] ) == -1 ) )
+                               {
+                                       int found = 0;
+                                       for ( i = 0; i < count; i++ )
+                                       {
+                                               octlet_t guid;
+                                               dv1394d_log( LOG_DEBUG, "attempting to get guid for node %d", i );
+                                               guid = rom1394_get_guid( handle, i );
+                                               if ( guid == g_units[ j ]->guid )
+                                               {
+                                                       dv1394d_log( LOG_NOTICE, "unit with GUID %08x%08x found", 
+                                                               (quadlet_t) (g_units[j]->guid>>32), (quadlet_t) (g_units[j]->guid & 0xffffffff));
+                                                       if ( dv_unit_is_offline( g_units[ j ] ) )
+                                                               dv_unit_online( g_units[ j ] );
+                                                       else
+                                                               dv_unit_restore( g_units[ j ] );
+                                                       found = 1;
+                                                       break;
+                                               }
+                                       }
+                                       if ( found == 0 )
+                                               dv_unit_offline( g_units[ j ] );
+                               }
+                       }
+                       dv1394d_log( LOG_DEBUG, "completed bus reset handler");
+                       raw1394_close( handle );
+                       return 0;
+               }
+               raw1394_close( handle );
+       }
+       dv1394d_log( LOG_CRIT, "raw1394 reported zero nodes on the bus!" );
+       return 0;
+}
+
+
+/** One pthread per IEEE 1394 port
+*/
+
+static pthread_t raw1394service_thread[4];
+
+/** One raw1394 handle for each pthread/port
+*/
+
+static raw1394handle_t raw1394service_handle[4];
+
+/** The service thread that polls raw1394 for new events.
+*/
+
+static void* raw1394_service( void *arg )
+{
+       raw1394handle_t handle = (raw1394handle_t) arg;
+       struct pollfd raw1394_poll;
+       raw1394_poll.fd = raw1394_get_fd( handle );
+       raw1394_poll.events = POLLIN;
+       raw1394_poll.revents = 0;
+       while ( 1 )
+       {
+               if ( poll( &raw1394_poll, 1, 200) > 0 )
+               {
+                       if ( (raw1394_poll.revents & POLLIN) 
+                                       || (raw1394_poll.revents & POLLPRI) )
+                               raw1394_loop_iterate( handle );
+               }
+               pthread_testcancel();
+       }
+       
+}
+
+
+/** Start the raw1394 service threads for handling bus reset.
+
+    One thread is launched per port on the system.
+*/
+
+void raw1394_start_service_threads( void )
+{
+       int port;
+       for ( port = 0; port < raw1394_get_num_ports(); port++ )
+       {
+               raw1394service_handle[port] = raw1394_open( port );
+               raw1394_set_bus_reset_handler( raw1394service_handle[port], reset_handler );
+               pthread_create( &(raw1394service_thread[port]), NULL, raw1394_service, raw1394service_handle[port] );
+       }
+       for ( ; port < 4; port++ )
+               raw1394service_handle[port] = NULL;
+}
+
+/** Shutdown all the raw1394 service threads.
+*/
+
+void raw1394_stop_service_threads( void )
+{
+       int i;
+       for ( i = 0; i < 4; i++ )
+       {
+               if ( raw1394service_handle[i] != NULL )
+               {
+                       pthread_cancel( raw1394service_thread[i] );
+                       pthread_join( raw1394service_thread[i], NULL );
+                       raw1394_close( raw1394service_handle[i] );
+               }
+       }
+}
+
+
diff --git a/mlt/src/miracle/miracle_commands.h b/mlt/src/miracle/miracle_commands.h
new file mode 100644 (file)
index 0000000..6c60d7d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * global_commands.h
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef _GLOBAL_COMMANDS_H_
+#define _GLOBAL_COMMANDS_H_
+
+#include <dv1394status.h>
+#include "dvunit.h"
+#include "dvconnection.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+dv_unit dv1394d_get_unit( int );
+void dv1394d_delete_unit( int );
+void dv1394d_delete_all_units( void );
+int dv1394d_unit_status( int n, dv1394_status status, int root_offset );
+void raw1394_start_service_threads( void );
+void raw1394_stop_service_threads( void );
+
+extern response_codes dv1394d_add_unit( command_argument );
+extern response_codes dv1394d_list_nodes( command_argument );
+extern response_codes dv1394d_list_units( command_argument );
+extern response_codes dv1394d_list_clips( command_argument );
+extern response_codes dv1394d_set_global_property( command_argument );
+extern response_codes dv1394d_get_global_property( command_argument );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/miracle/miracle_connection.c b/mlt/src/miracle/miracle_connection.c
new file mode 100644 (file)
index 0000000..6c65e35
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * dvconnection.c -- DV Connection Handler
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+#include <netdb.h>
+#include <sys/socket.h> 
+#include <arpa/inet.h>
+
+/* Application header files */
+#include "global_commands.h"
+#include "dvconnection.h"
+#include "dvsocket.h"
+#include "dvserver.h"
+#include "log.h"
+
+/** This is a generic replacement for fgets which operates on a file
+   descriptor. Unlike fgets, we can also specify a line terminator. Maximum
+   of (max - 1) chars can be read into buf from fd. If we reach the
+   end-of-file, *eof_chk is set to 1. 
+*/
+
+int fdgetline( int fd, char *buf, int max, char line_terminator, int *eof_chk )
+{
+       int count = 0;
+       char tmp [1];
+       *eof_chk = 0;
+       
+       if (fd)
+               while (count < max - 1) {
+                       if (read (fd, tmp, 1) > 0) {
+                               if (tmp [0] != line_terminator)
+                                       buf [count++] = tmp [0];
+                               else
+                                       break;
+
+/* Is it an EOF character (ctrl-D, i.e. ascii 4)? If so we definitely want
+   to break. */
+
+                               if (tmp [0] == 4) {
+                                       *eof_chk = 1;
+                                       break;
+                               }
+                       } else {
+                               *eof_chk = 1;
+                               break;
+                       }
+               }
+               
+       buf [count] = '\0';
+       
+       return count;
+}
+
+static int connection_initiate( int );
+static int connection_send( int, dv_response );
+static int connection_read( int, char *, int );
+static void connection_close( int );
+
+static int connection_initiate( int fd )
+{
+       int error = 0;
+       dv_response response = dv_response_init( );
+       dv_response_set_error( response, 100, "VTR Ready" );
+       error = connection_send( fd, response );
+       dv_response_close( response );
+       return error;
+}
+
+static int connection_send( int fd, dv_response response )
+{
+       int error = 0;
+       int index = 0;
+       int code = dv_response_get_error_code( response );
+
+       if ( code != -1 )
+       {
+               int items = dv_response_count( response );
+
+               if ( items == 0 )
+                       dv_response_set_error( response, 500, "Unknown error" );
+
+               if ( code == 200 && items > 2 )
+                       dv_response_set_error( response, 201, "OK" );
+               else if ( code == 200 && items > 1 )
+                       dv_response_set_error( response, 202, "OK" );
+
+               code = dv_response_get_error_code( response );
+               items = dv_response_count( response );
+
+               for ( index = 0; !error && index < items; index ++ )
+               {
+                       char *line = dv_response_get_line( response, index );
+                       int length = strlen( line );
+                       if ( length == 0 && index != dv_response_count( response ) - 1 && write( fd, " ", 1 ) != 1 )
+                               error = -1;
+                       else if ( length > 0 && write( fd, line, length ) != length )
+                               error = -1;
+                       if ( write( fd, "\r\n", 2 ) != 2 )
+                               error = -1;                     
+               }
+
+               if ( ( code == 201 || code == 500 ) && strcmp( dv_response_get_line( response, items - 1 ), "" ) )
+                       write( fd, "\r\n", 2 );
+       }
+       else
+       {
+               char *message = "500 Empty Response\r\n\r\n";
+               write( fd, message, strlen( message ) );
+       }
+
+       return error;
+}
+
+static int connection_read( int fd, char *command, int length )
+{
+       int eof_chk;
+       int nchars = fdgetline( fd, command, length, '\n', &eof_chk );
+       char *cr = strchr( command, '\r');
+       if ( cr != NULL ) 
+               cr[0] = '\0';
+       if ( eof_chk || strncmp( command, "BYE", 3 ) == 0 ) 
+               nchars = 0;
+       return nchars;
+}
+
+int connection_status( int fd, dv1394_notifier notifier )
+{
+       int error = 0;
+       int index = 0;
+       dv1394_status_t status;
+       char text[ 10240 ];
+       dv_socket socket = dv_socket_init_fd( fd );
+       
+       for ( index = 0; !error && index < MAX_UNITS; index ++ )
+       {
+               dv1394_notifier_get( notifier, &status, index );
+               dv1394_status_serialise( &status, text, sizeof( text ) );
+               error = dv_socket_write_data( socket, text, strlen( text )  ) != strlen( text );
+       }
+
+       while ( !error )
+       {
+               if ( dv1394_notifier_wait( notifier, &status ) == 0 )
+               {
+                       dv1394_status_serialise( &status, text, sizeof( text ) );
+                       error = dv_socket_write_data( socket, text, strlen( text ) ) != strlen( text );
+               }
+               else
+               {
+                       struct timeval tv = { 0, 0 };
+                       fd_set rfds;
+
+                   FD_ZERO( &rfds );
+                   FD_SET( fd, &rfds );
+
+                       if ( select( socket->fd + 1, &rfds, NULL, NULL, &tv ) )
+                               error = 1;
+               }
+       }
+
+       dv_socket_close( socket );
+       
+       return error;
+}
+
+static void connection_close( int fd )
+{
+       close( fd );
+}
+
+void *parser_thread( void *arg )
+{
+       struct hostent *he;
+       connection_t *connection = arg;
+       char address[ 512 ];
+       char command[ 1024 ];
+       int fd = connection->fd;
+       dv_parser parser = connection->parser;
+       dv_response response = NULL;
+
+       /* We definitely want to ignore broken pipes. */
+    signal( SIGPIPE, SIG_IGN );
+
+       /* Get the connecting clients ip information */
+       he = gethostbyaddr( (char *) &( connection->sin.sin_addr.s_addr ), sizeof(u_int32_t), AF_INET); 
+       if ( he != NULL )
+               strcpy( address, he->h_name );
+       else
+               inet_ntop( AF_INET, &( connection->sin.sin_addr.s_addr), address, 32 );
+
+       dv1394d_log( LOG_NOTICE, "Connection established with %s (%d)", address, fd );
+
+       /* Execute the commands received. */
+       if ( connection_initiate( fd ) == 0 )
+       {
+               int error = 0;
+
+               while( !error && connection_read( fd, command, 1024 ) )
+               {
+                       if ( strncmp( command, "STATUS", 6 ) )
+                       {
+                               response = dv_parser_execute( parser, command );
+                               dv1394d_log( LOG_INFO, "%s \"%s\" %d", address, command, dv_response_get_error_code( response ) );
+                               error = connection_send( fd, response );
+                               dv_response_close( response );
+                       }
+                       else
+                       {
+                               error = connection_status( fd, dv_parser_get_notifier( parser ) );
+                       }
+               }
+       }
+
+       /* Free the resources associated with this connection. */
+       connection_close( fd );
+
+       dv1394d_log( LOG_NOTICE, "Connection with %s (%d) closed", address, fd );
+
+       free( connection );
+
+       return NULL;
+}
diff --git a/mlt/src/miracle/miracle_connection.h b/mlt/src/miracle/miracle_connection.h
new file mode 100644 (file)
index 0000000..1c5d00b
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * dvconnection.h -- DV Connection Handler
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DV_CONNECTION_H_
+#define _DV_CONNECTION_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <dvparser.h>
+#include <dvtokeniser.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Connection structure
+*/
+
+typedef struct 
+{
+       int fd;
+       struct sockaddr_in sin;
+       dv_parser parser;
+} 
+connection_t;
+
+/** Enumeration for responses.
+*/
+
+typedef enum 
+{
+       RESPONSE_SUCCESS = 200,
+       RESPONSE_SUCCESS_N = 201,
+       RESPONSE_SUCCESS_1 = 202,
+       RESPONSE_UNKNOWN_COMMAND = 400,
+       RESPONSE_TIMEOUT = 401,
+       RESPONSE_MISSING_ARG = 402,
+       RESPONSE_INVALID_UNIT = 403,
+       RESPONSE_BAD_FILE = 404,
+       RESPONSE_OUT_OF_RANGE = 405,
+       RESPONSE_TOO_MANY_FILES = 406,
+       RESPONSE_ERROR = 500
+} 
+response_codes;
+
+/* the following struct is passed as the single argument 
+   to all command callback functions */
+
+typedef struct 
+{
+       dv_parser    parser;
+       dv_response  response;
+       dv_tokeniser tokeniser;
+       char         *command;
+       int           unit;
+       void         *argument;
+       char         *root_dir;
+} 
+command_argument_t, *command_argument;
+
+/* A handler is defined as follows. */
+typedef int (*command_handler_t) ( command_argument );
+
+
+extern void *parser_thread( void *arg );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/miracle/miracle_local.c b/mlt/src/miracle/miracle_local.c
new file mode 100644 (file)
index 0000000..fce4ab2
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * dvlocal.c -- Local dv1394d Parser
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* System header files */
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+/* Library header files */
+#include <dvutil.h>
+
+/* Application header files */
+#include <dvclipfactory.h>
+#include <dvframepool.h>
+#include "dvlocal.h"
+#include "dvconnection.h"
+#include "global_commands.h"
+#include "unit_commands.h"
+#include "log.h"
+#include "raw1394util.h"
+
+/** Private dv_local structure.
+*/
+
+typedef struct
+{
+       dv_parser parser;
+       char root_dir[1024];
+}
+*dv_local, dv_local_t;
+
+/** Forward declarations.
+*/
+
+static dv_response dv_local_connect( dv_local );
+static dv_response dv_local_execute( dv_local, char * );
+static void dv_local_close( dv_local );
+response_codes print_help( command_argument arg );
+response_codes dv1394d_run( command_argument arg );
+response_codes dv1394d_shutdown( command_argument arg );
+
+/** DV Parser constructor.
+*/
+
+dv_parser dv_parser_init_local( )
+{
+       dv_parser parser = malloc( sizeof( dv_parser_t ) );
+       dv_local local = malloc( sizeof( dv_local_t ) );
+
+       if ( parser != NULL )
+       {
+               memset( parser, 0, sizeof( dv_parser_t ) );
+
+               parser->connect = (parser_connect)dv_local_connect;
+               parser->execute = (parser_execute)dv_local_execute;
+               parser->close = (parser_close)dv_local_close;
+               parser->real = local;
+
+               if ( local != NULL )
+               {
+                       memset( local, 0, sizeof( dv_local_t ) );
+                       local->parser = parser;
+                       local->root_dir[0] = '/';
+               }
+       }
+       return parser;
+}
+
+/** response status code/message pair 
+*/
+
+typedef struct 
+{
+       int code;
+       char *message;
+} 
+responses_t;
+
+/** response messages 
+*/
+
+static responses_t responses [] = 
+{
+       {RESPONSE_SUCCESS, "OK"},
+       {RESPONSE_SUCCESS_N, "OK"},
+       {RESPONSE_SUCCESS_1, "OK"},
+       {RESPONSE_UNKNOWN_COMMAND, "Unknown command"},
+       {RESPONSE_TIMEOUT, "Operation timed out"},
+       {RESPONSE_MISSING_ARG, "Argument missing"},
+       {RESPONSE_INVALID_UNIT, "Unit not found"},
+       {RESPONSE_BAD_FILE, "Failed to locate or open clip"},
+       {RESPONSE_OUT_OF_RANGE, "Argument value out of range"},
+       {RESPONSE_TOO_MANY_FILES, "Too many files open"},
+       {RESPONSE_ERROR, "Server Error"}
+};
+
+/** Argument types.
+*/
+
+typedef enum 
+{
+       ATYPE_NONE,
+       ATYPE_FLOAT,
+       ATYPE_STRING,
+       ATYPE_INT
+} 
+arguments_types;
+
+/** A command definition.
+*/
+
+typedef struct 
+{
+/* The command string corresponding to this operation (e.g. "play") */
+       char *command;
+/* The function associated with it */
+       response_codes (*operation) ( command_argument );
+/* a boolean to indicate if this is a unit or global command
+   unit commands require a unit identifier as first argument */
+       int is_unit;
+/* What type is the argument (RTTI :-) ATYPE_whatever */
+       int type;
+/* online help information */
+       char *help;
+} 
+command_t;
+
+/* The following define the queue of commands available to the user. The
+   first entry is the name of the command (the string which must be typed),
+   the second command is the function associated with it, the third argument
+   is for the type of the argument, and the last argument specifies whether
+   this is something which should be handled immediately or whether it
+   should be queued (only robot motion commands need to be queued). */
+
+static command_t vocabulary[] = 
+{
+       {"BYE", NULL, 0, ATYPE_NONE, "Terminates the session. Units are not removed and task queue is not flushed."},
+       {"HELP", print_help, 0, ATYPE_NONE, "Display this information!"},
+       {"NLS", dv1394d_list_nodes, 0, ATYPE_NONE, "List the AV/C nodes on the 1394 bus."},
+       {"UADD", dv1394d_add_unit, 0, ATYPE_STRING, "Create a new DV unit (virtual VTR) to transmit to receiver specified in GUID argument."},
+       {"ULS", dv1394d_list_units, 0, ATYPE_NONE, "Lists the units that have already been added to the server."},
+       {"CLS", dv1394d_list_clips, 0, ATYPE_STRING, "Lists the clips at directory name argument."},
+       {"SET", dv1394d_set_global_property, 0, ATYPE_STRING, "Set a server configuration property."},
+       {"GET", dv1394d_get_global_property, 0, ATYPE_STRING, "Get a server configuration property."},
+       {"RUN", dv1394d_run, 0, ATYPE_STRING, "Run a batch file." },
+       {"LIST", dv1394d_list, 1, ATYPE_NONE, "List the playlist associated to a unit."},
+       {"LOAD", dv1394d_load, 1, ATYPE_STRING, "Load clip specified in absolute filename argument."},
+       {"INSERT", dv1394d_insert, 1, ATYPE_STRING, "Insert a clip at the given clip index."},
+       {"REMOVE", dv1394d_remove, 1, ATYPE_NONE, "Remove a clip at the given clip index."},
+       {"CLEAN", dv1394d_clean, 1, ATYPE_NONE, "Clean a unit by removing all but the currently playing clip."},
+       {"MOVE", dv1394d_move, 1, ATYPE_INT, "Move a clip to another clip index."},
+       {"APND", dv1394d_append, 1, ATYPE_STRING, "Append a clip specified in absolute filename argument."},
+       {"PLAY", dv1394d_play, 1, ATYPE_NONE, "Play a loaded clip at speed -2000 to 2000 where 1000 = normal forward speed."},
+       {"STOP", dv1394d_stop, 1, ATYPE_NONE, "Stop a loaded and playing clip."},
+       {"PAUSE", dv1394d_pause, 1, ATYPE_NONE, "Pause a playing clip."},
+       {"REW", dv1394d_rewind, 1, ATYPE_NONE, "Rewind a unit. If stopped, seek to beginning of clip. If playing, play fast backwards."},
+       {"FF", dv1394d_ff, 1, ATYPE_NONE, "Fast forward a unit. If stopped, seek to beginning of clip. If playing, play fast forwards."},
+       {"STEP", dv1394d_step, 1, ATYPE_INT, "Step argument number of frames forward or backward."},
+       {"GOTO", dv1394d_goto, 1, ATYPE_INT, "Jump to frame number supplied as argument."},
+       {"SIN", dv1394d_set_in_point, 1, ATYPE_INT, "Set the IN point of the loaded clip to frame number argument. -1 = reset in point to 0"},
+       {"SOUT", dv1394d_set_out_point, 1, ATYPE_INT, "Set the OUT point of the loaded clip to frame number argument. -1 = reset out point to maximum."},
+       {"USTA", dv1394d_get_unit_status, 1, ATYPE_NONE, "Report information about the unit."},
+       {"USET", dv1394d_set_unit_property, 1, ATYPE_STRING, "Set a unit configuration property."},
+       {"UGET", dv1394d_get_unit_property, 1, ATYPE_STRING, "Get a unit configuration property."},
+       {"XFER", dv1394d_transfer, 1, ATYPE_STRING, "Transfer the unit's clip to another unit specified as argument."},
+       {"SHUTDOWN", dv1394d_shutdown, 0, ATYPE_NONE, "Shutdown the server."},
+       {NULL, NULL, 0, ATYPE_NONE, NULL}
+};
+
+/** Usage message 
+*/
+
+static char helpstr [] = 
+       "dv1394d -- A DV over IEEE 1394 TCP Server\n" 
+       "       Copyright (C) 2002-2003 Ushodaya Enterprises Limited\n"
+       "       Authors:\n"
+       "               Dan Dennedy <dan@dennedy.org>\n"
+       "               Charles Yates <charles.yates@pandora.be>\n"
+       "Available commands:\n";
+
+/** Lookup the response message for a status code.
+*/
+
+inline char *get_response_msg( int code )
+{
+       int i = 0;
+       for ( i = 0; responses[ i ].message != NULL && code != responses[ i ].code; i ++ ) ;
+       return responses[ i ].message;
+}
+
+/** Tell the user the dv1394d command set
+*/
+
+response_codes print_help( command_argument cmd_arg )
+{
+       int i = 0;
+       
+       dv_response_printf( cmd_arg->response, 10240, "%s", helpstr );
+       
+       for ( i = 0; vocabulary[ i ].command != NULL; i ++ )
+               dv_response_printf( cmd_arg->response, 1024,
+                                                       "%-10.10s%s\n", 
+                                                       vocabulary[ i ].command, 
+                                                       vocabulary[ i ].help );
+
+       dv_response_printf( cmd_arg->response, 2, "\n" );
+
+       return RESPONSE_SUCCESS_N;
+}
+
+/** Execute a batch file.
+*/
+
+response_codes dv1394d_run( command_argument cmd_arg )
+{
+       dv_response temp = dv_parser_run( cmd_arg->parser, (char *)cmd_arg->argument );
+
+       if ( temp != NULL )
+       {
+               int index = 0;
+
+               dv_response_set_error( cmd_arg->response, 
+                                                          dv_response_get_error_code( temp ),
+                                                          dv_response_get_error_string( temp ) );
+
+               for ( index = 1; index < dv_response_count( temp ); index ++ )
+                       dv_response_printf( cmd_arg->response, 10240, "%s\n", dv_response_get_line( temp, index ) );
+
+               dv_response_close( temp );
+       }
+
+       return dv_response_get_error_code( cmd_arg->response );
+}
+
+response_codes dv1394d_shutdown( command_argument cmd_arg )
+{
+       exit( 0 );
+       return RESPONSE_SUCCESS;
+}
+
+/** Processes 'thread' id
+*/
+
+static pthread_t self;
+
+/* Signal handler to deal with various shutdown signals. Basically this
+   should clean up and power down the motor. Note that the death of any
+   child thread will kill all thrads. */
+
+void signal_handler( int sig )
+{
+       if ( pthread_equal( self, pthread_self( ) ) )
+       {
+
+#ifdef _GNU_SOURCE
+               dv1394d_log( LOG_DEBUG, "Received %s - shutting down.", strsignal(sig) );
+#else
+               dv1394d_log( LOG_DEBUG, "Received signal %i - shutting down.", sig );
+#endif
+
+               exit(EXIT_SUCCESS);
+       }
+}
+
+/** Local 'connect' function.
+*/
+
+static dv_response dv_local_connect( dv_local local )
+{
+       dv_response response = dv_response_init( );
+
+       self = pthread_self( );
+
+       dv_response_set_error( response, 100, "VTR Ready" );
+
+       signal( SIGHUP, signal_handler );
+       signal( SIGINT, signal_handler );
+       signal( SIGTERM, signal_handler );
+       signal( SIGSTOP, signal_handler );
+       signal( SIGCHLD, SIG_IGN );
+       
+       raw1394_reconcile_bus();
+       /* Start the raw1394 service threads for handling bus resets */
+       raw1394_start_service_threads();
+
+       return response;
+}
+
+/** Set the error and determine the message associated to this command.
+*/
+
+void dv_command_set_error( command_argument cmd, response_codes code )
+{
+       dv_response_set_error( cmd->response, code, get_response_msg( code ) );
+}
+
+/** Parse the unit argument.
+*/
+
+int dv_command_parse_unit( command_argument cmd, int argument )
+{
+       int unit = -1;
+       char *string = dv_tokeniser_get_string( cmd->tokeniser, argument );
+       if ( string != NULL && ( string[ 0 ] == 'U' || string[ 0 ] == 'u' ) && strlen( string ) > 1 )
+               unit = atoi( string + 1 );
+       return unit;
+}
+
+/** Parse a normal argument.
+*/
+
+void *dv_command_parse_argument( command_argument cmd, int argument, arguments_types type )
+{
+       void *ret = NULL;
+       char *value = dv_tokeniser_get_string( cmd->tokeniser, argument );
+
+       if ( value != NULL )
+       {
+               switch( type )
+               {
+                       case ATYPE_NONE:
+                               break;
+
+                       case ATYPE_FLOAT:
+                               ret = malloc( sizeof( float ) );
+                               if ( ret != NULL )
+                                       *( float * )ret = atof( value );
+                               break;
+
+                       case ATYPE_STRING:
+                               ret = strdup( value );
+                               break;
+                                       
+                       case ATYPE_INT:
+                               ret = malloc( sizeof( int ) );
+                               if ( ret != NULL )
+                                       *( int * )ret = atoi( value );
+                               break;
+               }
+       }
+
+       return ret;
+}
+
+/** Get the error code - note that we simply the success return.
+*/
+
+response_codes dv_command_get_error( command_argument cmd )
+{
+       response_codes ret = dv_response_get_error_code( cmd->response );
+       if ( ret == RESPONSE_SUCCESS_N || ret == RESPONSE_SUCCESS_1 )
+               ret = RESPONSE_SUCCESS;
+       return ret;
+}
+
+/** Execute the command.
+*/
+
+static dv_response dv_local_execute( dv_local local, char *command )
+{
+       command_argument_t cmd;
+       cmd.parser = local->parser;
+       cmd.response = dv_response_init( );
+       cmd.tokeniser = dv_tokeniser_init( );
+       cmd.command = command;
+       cmd.unit = -1;
+       cmd.argument = NULL;
+       cmd.root_dir = local->root_dir;
+
+       /* Set the default error */
+       dv_command_set_error( &cmd, RESPONSE_UNKNOWN_COMMAND );
+
+       /* Parse the command */
+       if ( dv_tokeniser_parse_new( cmd.tokeniser, command, " " ) > 0 )
+       {
+               int index = 0;
+               char *value = dv_tokeniser_get_string( cmd.tokeniser, 0 );
+               int found = 0;
+
+               /* Strip quotes from all tokens */
+               for ( index = 0; index < dv_tokeniser_count( cmd.tokeniser ); index ++ )
+                       dv_util_strip( dv_tokeniser_get_string( cmd.tokeniser, index ), '\"' );
+
+               /* Search the vocabulary array for value */
+               for ( index = 1; !found && vocabulary[ index ].command != NULL; index ++ )
+                       if ( ( found = !strcasecmp( vocabulary[ index ].command, value ) ) )
+                               break;
+
+               /* If we found something, the handle the args and call the handler. */
+               if ( found )
+               {
+                       int position = 1;
+
+                       dv_command_set_error( &cmd, RESPONSE_SUCCESS );
+
+                       if ( vocabulary[ index ].is_unit )
+                       {
+                               cmd.unit = dv_command_parse_unit( &cmd, position );
+                               if ( cmd.unit == -1 )
+                                       dv_command_set_error( &cmd, RESPONSE_MISSING_ARG );
+                               position ++;
+                       }
+
+                       if ( dv_command_get_error( &cmd ) == RESPONSE_SUCCESS )
+                       {
+                               cmd.argument = dv_command_parse_argument( &cmd, position, vocabulary[ index ].type );
+                               if ( cmd.argument == NULL && vocabulary[ index ].type != ATYPE_NONE )
+                                       dv_command_set_error( &cmd, RESPONSE_MISSING_ARG );
+                               position ++;
+                       }
+
+                       if ( dv_command_get_error( &cmd ) == RESPONSE_SUCCESS )
+                       {
+                               response_codes error = vocabulary[ index ].operation( &cmd );
+                               dv_command_set_error( &cmd, error );
+                       }
+
+                       free( cmd.argument );
+               }
+       }
+
+       dv_tokeniser_close( cmd.tokeniser );
+
+       return cmd.response;
+}
+
+/** Close the parser.
+*/
+
+static void dv_local_close( dv_local local )
+{
+       raw1394_stop_service_threads();
+       dv1394d_delete_all_units();
+       pthread_kill_other_threads_np();
+       dv1394d_log( LOG_DEBUG, "Clean shutdown." );
+       free( local );
+       dv_clip_factory_close( );
+       dv_frame_pool_close( );
+}
diff --git a/mlt/src/miracle/miracle_local.h b/mlt/src/miracle/miracle_local.h
new file mode 100644 (file)
index 0000000..fbbe444
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * dvlocal.h -- Local dv1394d Parser
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _DV_LOCAL_H_
+#define _DV_LOCAL_H_
+
+/* Application header files */
+#include <dvparser.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Local parser API.
+*/
+
+extern dv_parser dv_parser_init_local( );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/miracle/miracle_log.c b/mlt/src/miracle/miracle_log.c
new file mode 100644 (file)
index 0000000..cdb5d82
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * log.h -- logging facility implementation
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdarg.h>
+#include <syslog.h>
+#include <stdio.h>
+
+#include "log.h"
+
+static int log_output = log_stderr;
+static int threshold = LOG_DEBUG;
+
+void
+dv1394d_log_init( enum log_output method, int new_threshold )
+{
+       log_output = method;
+       threshold = new_threshold;
+       if (method == log_syslog)
+               openlog( "dv1394d", LOG_CONS, LOG_DAEMON );
+
+}
+
+void
+dv1394d_log( int priority, char *format, ... )
+{
+       va_list list;
+       va_start( list, format );
+       if ( LOG_PRI(priority) <= threshold )
+       {
+               if ( log_output == log_syslog )
+               {
+                               vsyslog( priority, format, list );
+               }
+               else
+               {
+                       char line[1024];
+                       if ( snprintf( line, 1024, "(%d) %s\n", priority, format ) != 0 )
+                               vfprintf( stderr, line, list );
+               }
+       }
+       va_end( list );
+}
diff --git a/mlt/src/miracle/miracle_log.h b/mlt/src/miracle/miracle_log.h
new file mode 100644 (file)
index 0000000..04505e9
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * log.h -- logging facility header
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include <syslog.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+enum log_output {
+       log_stderr,
+       log_syslog
+};
+
+void dv1394d_log_init( enum log_output method, int threshold );
+void dv1394d_log( int priority, char *format, ... );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/miracle/miracle_server.c b/mlt/src/miracle/miracle_server.c
new file mode 100644 (file)
index 0000000..d4f886b
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * dvserver.c -- DV Server
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <string.h>
+#include <netinet/in.h>
+#include "log.h"
+#include <netdb.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+/* Application header files */
+#include "dvserver.h"
+#include "dvconnection.h"
+#include "dvlocal.h"
+#include "log.h"
+#include <dvremote.h>
+#include <dvtokeniser.h>
+
+/** Initialise a server structure.
+*/
+
+dv_server dv_server_init( char *id )
+{
+       dv_server server = malloc( sizeof( dv_server_t ) );
+       if ( server != NULL )
+       {
+               memset( server, 0, sizeof( dv_server_t ) );
+               server->id = id;
+               server->port = DEFAULT_TCP_PORT;
+               server->socket = -1;
+       }
+       return server;
+}
+
+/** Set the port of the server.
+*/
+
+void dv_server_set_port( dv_server server, int port )
+{
+       server->port = port;
+}
+
+void dv_server_set_proxy( dv_server server, char *proxy )
+{
+       dv_tokeniser tokeniser = dv_tokeniser_init( );
+       server->proxy = 1;
+       server->remote_port = DEFAULT_TCP_PORT;
+       dv_tokeniser_parse_new( tokeniser, proxy, ":" );
+       strcpy( server->remote_server, dv_tokeniser_get_string( tokeniser, 0 ) );
+       if ( dv_tokeniser_count( tokeniser ) == 2 )
+               server->remote_port = atoi( dv_tokeniser_get_string( tokeniser, 1 ) );
+       dv_tokeniser_close( tokeniser );
+}
+
+/** Wait for a connection.
+*/
+
+static int dv_server_wait_for_connect( dv_server server )
+{
+    struct timeval tv;
+    fd_set rfds;
+
+    /* Wait for a 1 second. */
+    tv.tv_sec = 1;
+    tv.tv_usec = 0;
+
+    FD_ZERO( &rfds );
+    FD_SET( server->socket, &rfds );
+
+    return select( server->socket + 1, &rfds, NULL, NULL, &tv);
+}
+
+/** Run the server thread.
+*/
+
+static void *dv_server_run( void *arg )
+{
+       dv_server server = arg;
+       pthread_t cmd_parse_info;
+       connection_t *tmp = NULL;
+       pthread_attr_t thread_attributes;
+       int socksize;
+
+       socksize = sizeof( struct sockaddr );
+
+       dv1394d_log( LOG_NOTICE, "%s version %s listening on port %i", server->id, VERSION, server->port );
+
+       /* Create the initial thread. We want all threads to be created detached so
+          their resources get freed automatically. (CY: ... hmmph...) */
+       pthread_attr_init( &thread_attributes );
+       pthread_attr_setdetachstate( &thread_attributes, PTHREAD_CREATE_DETACHED );
+       pthread_attr_init( &thread_attributes );
+       pthread_attr_setinheritsched( &thread_attributes, PTHREAD_INHERIT_SCHED );
+       /* pthread_attr_setschedpolicy( &thread_attributes, SCHED_RR ); */
+
+       while ( !server->shutdown )
+       {
+               /* Wait for a new connection. */
+               if ( dv_server_wait_for_connect( server ) )
+               {
+                       /* Create a new block of data to hold a copy of the incoming connection for
+                          our server thread. The thread should free this when it terminates. */
+
+                       tmp = (connection_t*) malloc( sizeof(connection_t) );
+                       tmp->parser = server->parser;
+                       tmp->fd = accept( server->socket, (struct sockaddr*) &(tmp->sin), &socksize );
+
+                       /* Pass the connection to a parser thread :-/ */
+                       if ( tmp->fd != -1 )
+                               pthread_create( &cmd_parse_info, &thread_attributes, parser_thread, tmp );
+               }
+       }
+
+       dv1394d_log( LOG_NOTICE, "%s version %s server terminated.", server->id, VERSION );
+
+       return NULL;
+}
+
+/** Execute the server thread.
+*/
+
+int dv_server_execute( dv_server server )
+{
+       int error = 0;
+       dv_response response = NULL;
+       int index = 0;
+       struct sockaddr_in ServerAddr;
+       int flag = 1;
+
+       ServerAddr.sin_family = AF_INET;
+       ServerAddr.sin_port = htons( server->port );
+       ServerAddr.sin_addr.s_addr = INADDR_ANY;
+       
+       /* Create socket, and bind to port. Listen there. Backlog = 5
+          should be sufficient for listen (). */
+       server->socket = socket( AF_INET, SOCK_STREAM, 0 );
+
+       if ( server->socket == -1 )
+       {
+               server->shutdown = 1;
+               perror( "socket" );
+               dv1394d_log( LOG_ERR, "%s unable to create socket.", server->id );
+               return -1;
+       }
+
+    setsockopt( server->socket, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof( int ) );
+
+       if ( bind( server->socket, (struct sockaddr *) &ServerAddr, sizeof (ServerAddr) ) != 0 )
+       {
+               server->shutdown = 1;
+               perror( "bind" );
+               dv1394d_log( LOG_ERR, "%s unable to bind to port %d.", server->id, server->port );
+               return -1;
+       }
+
+       if ( listen( server->socket, 5 ) != 0 )
+       {
+               server->shutdown = 1;
+               perror( "listen" );
+               dv1394d_log( LOG_ERR, "%s unable to listen on port %d.", server->id, server->port );
+               return -1;
+       }
+
+       fcntl( server->socket, F_SETFL, O_NONBLOCK );
+
+       if ( !server->proxy )
+       {
+               dv1394d_log( LOG_NOTICE, "Starting server on %d.", server->port );
+               server->parser = dv_parser_init_local( );
+       }
+       else
+       {
+               dv1394d_log( LOG_NOTICE, "Starting proxy for %s:%d on %d.", server->remote_server, server->remote_port, server->port );
+               server->parser = dv_parser_init_remote( server->remote_server, server->remote_port );
+       }
+
+       response = dv_parser_connect( server->parser );
+
+       if ( response != NULL && dv_response_get_error_code( response ) == 100 )
+       {
+               /* read configuration file */
+               if ( response != NULL && !server->proxy )
+               {
+                       dv_response_close( response );
+                       response = dv_parser_run( server->parser, "/etc/dv1394d.conf" );
+
+                       if ( dv_response_count( response ) > 1 )
+                       {
+                               if ( dv_response_get_error_code( response ) > 299 )
+                                       dv1394d_log( LOG_ERR, "Error evaluating server configuration. Processing stopped." );
+                               for ( index = 0; index < dv_response_count( response ); index ++ )
+                                       dv1394d_log( LOG_DEBUG, "%4d: %s", index, dv_response_get_line( response, index ) );
+                       }
+               }
+
+               if ( response != NULL )
+               {
+                       pthread_attr_t attr;
+                       int result;
+                       pthread_attr_init( &attr );
+                       pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
+                       pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
+                       pthread_attr_setschedpolicy( &attr, SCHED_FIFO );
+                       pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );
+                       dv_response_close( response );
+                       result = pthread_create( &server->thread, &attr, dv_server_run, server );
+                       if ( result )
+                       {
+                               dv1394d_log( LOG_WARNING, "Failed to schedule realtime (%s)", strerror(errno) );
+                               pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
+                               result = pthread_create( &server->thread, &attr, dv_server_run, server );
+                               if ( result )
+                               {
+                                       dv1394d_log( LOG_CRIT, "Failed to launch TCP listener thread" );
+                                       error = -1;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               dv1394d_log( LOG_ERR, "Error connecting to parser. Processing stopped." );
+               server->shutdown = 1;
+               error = -1;
+       }
+
+       return error;
+}
+
+/** Shutdown the server.
+*/
+
+void dv_server_shutdown( dv_server server )
+{
+       if ( server != NULL && !server->shutdown )
+       {
+               server->shutdown = 1;
+               pthread_join( server->thread, NULL );
+               dv_parser_close( server->parser );
+               close( server->socket );
+       }
+}
diff --git a/mlt/src/miracle/miracle_server.h b/mlt/src/miracle/miracle_server.h
new file mode 100644 (file)
index 0000000..96b22ce
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * dvserver.h -- DV Server
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DV_SERVER_H_
+#define _DV_SERVER_H_
+
+/* System header files */
+#include <pthread.h>
+
+/* Application header files */
+#include <dvparser.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Servers default port
+*/
+
+#define DEFAULT_TCP_PORT 5250
+
+/** Structure for the server
+*/
+
+typedef struct
+{
+       char *id;
+       int port;
+       int socket;
+       dv_parser parser;
+       pthread_t thread;
+       int shutdown;
+       int proxy;
+       char remote_server[ 50 ];
+       int remote_port;
+}
+*dv_server, dv_server_t;
+
+/** API for the server
+*/
+
+extern dv_server dv_server_init( char * );
+extern void dv_server_set_port( dv_server, int );
+extern void dv_server_set_proxy( dv_server, char * );
+extern int dv_server_execute( dv_server );
+extern void dv_server_shutdown( dv_server );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/miracle/miracle_unit.c b/mlt/src/miracle/miracle_unit.c
new file mode 100644 (file)
index 0000000..bc8adcf
--- /dev/null
@@ -0,0 +1,1100 @@
+/*
+ * dvunit.c -- DV Transmission Unit Implementation
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <libdv/dv1394.h>
+#include <libraw1394/raw1394.h>
+#include <libavc1394/avc1394_vcr.h>
+#include <sys/mman.h>
+
+#include "dvunit.h"
+#include "dvframe.h"
+#include "dvframepool.h"
+#include "dvqueue.h"
+#include "dvpump.h"
+#include "dverror.h"
+#include "dvplayer.h"
+#include "raw1394util.h"
+#include "log.h"
+#include "dvlocal.h"
+
+/* Forward references */
+static void dv_unit_status_communicate( dv_unit );
+
+/** dv1394 device file names based upon devfs default names. */
+
+static char *devices[4][4] = {
+       {
+       "/dev/ieee1394/dv/host0/NTSC/in",
+       "/dev/ieee1394/dv/host0/NTSC/out",
+       "/dev/ieee1394/dv/host0/PAL/in",
+       "/dev/ieee1394/dv/host0/PAL/out",
+       },{
+       "/dev/ieee1394/dv/host1/NTSC/in",
+       "/dev/ieee1394/dv/host1/NTSC/out",
+       "/dev/ieee1394/dv/host1/PAL/in",
+       "/dev/ieee1394/dv/host1/PAL/out"
+       },{
+       "/dev/ieee1394/dv/host2/NTSC/in",
+       "/dev/ieee1394/dv/host2/NTSC/out",
+       "/dev/ieee1394/dv/host2/PAL/in",
+       "/dev/ieee1394/dv/host2/PAL/out"
+       },{
+       "/dev/ieee1394/dv/host3/NTSC/in",
+       "/dev/ieee1394/dv/host3/NTSC/out",
+       "/dev/ieee1394/dv/host3/PAL/in",
+       "/dev/ieee1394/dv/host3/PAL/out"
+       }
+};
+
+static int device_count[4] = {0,0,0,0};
+
+/** Allocate a new DV transmission unit.
+
+    \param dv1394d_fd The file descriptor of a dv1394 device file to 
+                      use for transmission.
+    \param guid The node GUID of the receiving device.
+    \param channel The channel to use for transmission.
+    \return A new dv_unit handle.
+*/
+
+dv_unit dv_unit_init( octlet_t guid, int channel )
+{
+       dv_unit unit = malloc( sizeof( dv_unit_t ) );
+       if ( unit != NULL )
+       {
+               int node_id;
+               
+               memset( unit, 0, sizeof( dv_unit_t ) );
+               unit->guid = guid;
+               unit->buffer_size = 25;
+               unit->is_terminated = 1;
+               unit->channel = channel;
+               unit->dv1394_fd = -1;
+               unit->n_frames = DV1394_MAX_FRAMES / 2;
+               unit->n_fill = 1;
+
+               /* get a raw1394 handle for plug control */
+               if ( ( node_id = raw1394_find_node( &(unit->raw1394), guid ) ) != -1 )
+               {
+                       if ( dv_unit_online( unit ) == 1 )
+                               dv1394d_log( LOG_DEBUG, "Added online unit with GUID %08x%08x", 
+                                       (quadlet_t) (unit->guid>>32), (quadlet_t) (unit->guid & 0xffffffff) );
+                       else
+                       {
+                               dv_unit_close( unit );
+                               unit = NULL;
+                       }
+               }
+               else
+               {
+                       dv1394d_log( LOG_DEBUG, "Added offline unit with GUID %08x%08x", 
+                               (quadlet_t) (unit->guid>>32), (quadlet_t) (unit->guid & 0xffffffff) );
+               }
+       }
+       return unit;
+}
+
+/** Allow stdin to feed the unit (redundant now that senddv has been dropped).
+*/
+
+void dv_unit_allow_stdin( dv_unit unit, int flag )
+{
+       unit->allow_stdin = flag;
+}
+
+/** Override the default buffer/pump size - this must be done prior to the pumps
+       creation.
+*/
+
+void dv_unit_set_buffer_size( dv_unit unit, int size )
+{
+       if ( size > 0 )
+       {
+               if ( unit->pump == NULL )
+                       unit->buffer_size = size;
+               else
+                       unit->buffer_size = dv_pump_resize( unit->pump, size );
+       }
+}
+
+int dv_unit_get_buffer_size( dv_unit unit )
+{
+       return unit->buffer_size;
+}
+
+void dv_unit_set_n_frames( dv_unit unit, int size )
+{
+       if ( size > 0 && size <= DV1394_MAX_FRAMES / 2 )
+               unit->n_frames = size;
+}
+
+int dv_unit_get_n_frames( dv_unit unit )
+{
+       return unit->n_frames;
+}
+
+void dv_unit_set_n_fill( dv_unit unit, int size )
+{
+       unit->n_fill = size;
+}
+
+int dv_unit_get_n_fill( dv_unit unit )
+{
+       return unit->n_fill;
+}
+
+/** Set the notifier info
+*/
+
+void dv_unit_set_notifier( dv_unit this, dv1394_notifier notifier, char *root_dir )
+{
+       this->notifier = notifier;
+       this->root_dir = root_dir;
+       dv_unit_status_communicate( this );
+}
+
+/** Communicate the current status to all threads waiting on the notifier.
+*/
+
+static void dv_unit_status_communicate( dv_unit unit )
+{
+       if ( unit != NULL && unit->notifier != NULL && unit->root_dir != NULL )
+       {
+               dv1394_status_t status;
+               if ( dv_unit_get_status( unit, &status ) == 0 )
+                       if ( !( ( status.status == unit_playing || status.status == unit_paused ) &&
+                                       strcmp( status.clip, "" ) && 
+                                   !strcmp( status.tail_clip, "" ) && 
+                                       status.position == 0 && 
+                                       status.in == 0 && 
+                                       status.out == 0 ) )
+                               dv1394_notifier_put( unit->notifier, &status );
+       }
+}
+
+/** Load a clip into the unit clearing existing play list.
+
+    \todo error handling
+    \param unit A dv_unit handle.
+    \param clip The absolute file name of the clip to load.
+    \param in   The starting frame (-1 for 0)
+       \param out  The ending frame (-1 for maximum)
+*/
+
+dv_error_code dv_unit_load( dv_unit unit, const char *clip, long in, long out, int flush )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_error_code error = dv_player_get_error( player );
+       if ( error == dv_pump_ok )
+       {
+               error = dv_player_replace_file( player, (char*) clip, in, out, flush );
+               dv1394d_log( LOG_DEBUG, "loaded clip %s", clip );
+               if ( unit->is_terminated )
+                       dv_unit_status_communicate( unit );
+       }
+       return error;
+}
+
+dv_error_code dv_unit_insert( dv_unit unit, const char *clip, int index, long in, long out )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_error_code error = dv_player_get_error( player );
+       if ( error == dv_pump_ok )
+       {
+               error = dv_player_insert_file( player, (char*) clip, index, in, out );
+               dv1394d_log( LOG_DEBUG, "inserted clip %s", clip );
+               if ( unit->is_terminated )
+                       dv_unit_status_communicate( unit );
+       }
+       return error;
+}
+
+dv_error_code dv_unit_remove( dv_unit unit, int index )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_error_code error = dv_player_get_error( player );
+       if ( error == dv_pump_ok )
+       {
+               error = dv_player_remove_clip( player, index );
+               dv1394d_log( LOG_DEBUG, "removed clip %d", index );
+               if ( unit->is_terminated )
+                       dv_unit_status_communicate( unit );
+       }
+       return error;
+}
+
+dv_error_code dv_unit_clean( dv_unit unit )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_error_code error = dv_player_get_error( player );
+       if ( error == dv_pump_ok )
+       {
+               error = dv_player_clean( player );
+               dv1394d_log( LOG_DEBUG, "Cleaned playlist" );
+               if ( unit->is_terminated )
+                       dv_unit_status_communicate( unit );
+       }
+       return error;
+}
+
+dv_error_code dv_unit_move( dv_unit unit, int src, int dest )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_error_code error = dv_player_get_error( player );
+       if ( error == dv_pump_ok )
+       {
+               error = dv_player_move_clip( player, src, dest );
+               dv1394d_log( LOG_DEBUG, "moved clip %d to %d", src, dest );
+               if ( unit->is_terminated )
+                       dv_unit_status_communicate( unit );
+       }
+       return error;
+}
+
+/** Add a clip to the unit play list.
+
+    \todo error handling
+    \param unit A dv_unit handle.
+    \param clip The absolute file name of the clip to load.
+    \param in   The starting frame (-1 for 0)
+       \param out  The ending frame (-1 for maximum)
+*/
+
+dv_error_code dv_unit_append( dv_unit unit, const char *clip, long in, long out )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_error_code error = dv_player_add_file( player, (char*) clip, in, out );
+       dv_unit_status_communicate( unit );
+       return error;
+}
+
+void *output_cleanup( void *arg )
+{
+       dv_unit unit = arg;
+       if ( unit != NULL && unit->mmap != NULL )
+       {
+               unit->is_terminated = 1;
+               dv_unit_status_communicate( unit );
+               munmap( unit->mmap, unit->mmap_length );
+               /* this actually stops transmission as opposed to allowing the 
+                  last frame to loop in the OHCI DMA context. */
+               ioctl( unit->dv1394_fd, DV1394_SHUTDOWN, NULL );
+       }
+
+       return NULL;
+}
+
+/** The dv1394 transmission thread.
+
+    \param arg A dv_unit handle.
+*/
+
+static void *output( void *arg )
+{
+       dv_unit unit = arg;
+       dv_frame frames[ DV1394_MAX_FRAMES ];
+       int frames_dropped = 0; /* count of total frames dropped (repeated) */
+       struct dv1394_status status;
+       char errstr[64];
+       int n_fill = unit->n_fill;
+       int n_frames = unit->n_frames;
+       
+       /* Determine the number of frames to wait for/fill on each iteration */
+       if ( n_fill < 1 )
+               n_fill = 1;
+       else if ( n_fill > unit->n_frames )
+               n_fill = n_frames / 2;
+
+       unit->mmap = mmap( NULL,unit->mmap_length,PROT_WRITE,MAP_SHARED,unit->dv1394_fd,0 );
+       if ( unit->mmap == MAP_FAILED || unit->mmap == NULL )
+       {
+               perror( "mmap" );
+               return NULL;
+       }
+
+       pthread_cleanup_push( output_cleanup, (void *)arg );
+
+       while ( dv_pump_get_available_output_count( unit->pump ) || 
+               !( dv_unit_has_terminated( unit ) || dv_pump_has_terminated( unit->pump) ) )
+       {
+               int available = 0;
+
+               if ( ioctl( unit->dv1394_fd, DV1394_WAIT_FRAMES, n_fill ) < 0)
+                       perror( "DV1394_WAIT_FRAMES" );
+
+               pthread_testcancel();
+
+               /* update the status for the next iteration and detect dropped frames */
+               if ( ioctl( unit->dv1394_fd, DV1394_GET_STATUS, &status ) >= 0)
+               {
+                       pthread_testcancel();
+
+                       /*
+                       printf( "dv1394 status: active=%02d, #clear=%02d, first clear=%02d\n", 
+                               status.active_frame, status.n_clear_frames, status.first_clear_frame);
+                       */
+               
+                       /* report dropped frames */
+                       if( status.dropped_frames > 0 )
+                       {
+                               frames_dropped += status.dropped_frames;
+                               dv1394d_log( LOG_WARNING, "dv1394 repeated %d frames with %d available.", 
+                                                        status.dropped_frames, dv_pump_get_available_output_count( unit->pump ) );
+                       }
+
+                       available = dv_pump_get_output_block( unit->pump, (void **)frames, n_fill );
+
+                       dv_unit_status_communicate( unit );
+                       
+                       /* The only time we get 0 frames is when the unit is being stopped. */
+                       if ( available != 0 )
+                       {
+                               int size = dv_frame_size( frames[ 0 ] );
+                               int pos = status.first_clear_frame;
+                               int index = 0;
+
+                               for ( index = 0; index < available; index ++ )
+                                       memcpy( unit->mmap + ( ( pos + index ) % n_frames ) * size, dv_frame_data( frames[ index ] ), size );
+
+                               if ( ioctl( unit->dv1394_fd, DV1394_SUBMIT_FRAMES, available ) >= 0)
+                               {
+                                       for ( index = 0; index < available - 1; index ++ )
+                                       {
+                                               dv_frame_clear_error( frames[ index ] );
+                                               dv_frame_id_clear( dv_frame_get_id( frames[ index ] ) );
+                                       }                       
+                                       dv_pump_return_output_block( unit->pump );
+                                       pthread_testcancel();
+                               }
+                               else
+                               {
+                                       dv1394d_log( LOG_ERR, "failed to write frames to dv1394: %s.", strerror_r( errno, errstr, 63 ) );
+                                       dv_pump_terminate( unit->pump );
+                                       dv_pump_flush( unit->pump );
+                                       pthread_testcancel();
+                               }
+                       }
+               }
+               else
+               {
+                       dv1394d_log( LOG_ERR, "failed to get dv1394 status: %s.", strerror_r( errno, errstr, 63 ) );
+                       dv_pump_return_used_output( unit->pump );
+               }
+       }
+
+       if ( frames_dropped > 0 )
+               dv1394d_log( LOG_WARNING, "dv1394 repeated %d frames total during this transmission.", frames_dropped );
+
+       pthread_cleanup_pop( 1 );
+
+       return NULL;
+}
+
+/** Start playing the clip.
+
+    Start a dv-pump and commence dv1394 transmission.
+
+    \todo error handling
+    \param unit A dv_unit handle.
+    \param speed An integer that specifies the playback rate as a
+                 percentage multiplied by 100.
+*/
+
+void dv_unit_play( dv_unit_t *unit, int speed )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+
+       if ( unit->is_terminated == 1 && ( dv_player_get_total_frames( player ) > 0 || unit->allow_stdin ) )
+       {
+               int retval;
+               dv_frame frame = NULL;
+               struct dv1394_init setup =
+               {
+                       api_version: DV1394_API_VERSION,
+                       channel: unit->channel,
+                       /* this only sets the *requested* size of the ringbuffer,
+                          in frames */ 
+                       n_frames: unit->n_frames,
+                       /* we set the format later */
+                       cip_n: unit->dv1394_cip_n,
+                       cip_d: unit->dv1394_cip_d,
+                       syt_offset: unit->dv1394_syt_offset
+               };
+               pthread_attr_t attr;
+
+               if ( unit->in == NULL )
+               {
+                       if ( !unit->allow_stdin || dv_player_get_total_frames( player ) != 0 )
+                               unit->in = dv_player_get_dv_input( player );
+                       else
+                               unit->in = dv_input_init( unit->pump );
+               }
+               else
+               {
+                       dv_input_join_thread( unit->in );
+                       pthread_join( unit->out, NULL );
+               }
+
+               unit->is_terminated = 0;
+               dv_pump_restart( unit->pump );
+               dv_input_start_thread( unit->in );
+               dv_player_set_speed( player, (double) speed/1000.0 );
+
+               /* first we read a little data to see if this is PAL or NTSC
+                  so we can initialize dv1394 properly */
+               frame = dv_pump_get_available_output( unit->pump );
+       
+               /* initialize dv1394 */
+               setup.format = dv_frame_is_pal(frame) ? DV1394_PAL : DV1394_NTSC;
+               
+               retval = ioctl( unit->dv1394_fd, DV1394_INIT, &setup );
+               if (retval < 0)
+               {
+                       perror( "DV1394_INIT" );
+                       return;
+               }
+
+               unit->mmap_length = unit->n_frames * dv_frame_size( frame );
+
+               pthread_attr_init( &attr );
+               pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
+               pthread_attr_setinheritsched( &attr, PTHREAD_INHERIT_SCHED );
+               pthread_create( &unit->out, &attr, output, unit );
+       }
+       else 
+       {
+               dv_player_set_speed( player, (double) speed/1000.0 );
+       }
+       dv_unit_status_communicate( unit );
+}
+
+/** Stop playback.
+
+    Terminates the dv_pump and halts dv1394 transmission.
+
+    \param unit A dv_unit handle.
+*/
+
+void dv_unit_terminate( dv_unit unit )
+{
+       unit->is_terminated = 1;
+       if ( unit->pump != NULL )
+       {
+               dv_pump_terminate( unit->pump );
+               dv_pump_flush( unit->pump );
+       }
+}
+
+/** Query the status of unit playback.
+
+    \param unit A dv_unit handle.
+    \return 1 if the unit is not playing, 0 if playing.
+*/
+
+int dv_unit_has_terminated( dv_unit unit )
+{
+       return unit->is_terminated;
+}
+
+/** Get the dv_player from the dv_unit.
+
+    \param unit A dv_unit handle.
+    \return A dv_player handle.
+*/
+
+dv_player dv_unit_get_dv_player( dv_unit unit )
+{
+       if ( unit != NULL )
+       {
+               if ( unit->pump == NULL )
+               {
+                       unit->pump = dv_pump_init( unit->buffer_size );
+                       if ( unit->pump != NULL )
+                               unit->player = dv_player_init( unit->pump );
+               }
+               return unit->player;
+       }
+       return NULL;
+}
+
+
+/** Transfer the currently loaded clip to another unit
+*/
+
+int dv_unit_transfer( dv_unit dest_unit, dv_unit src_unit )
+{
+       dv_player src_player = dv_unit_get_dv_player( src_unit );
+       dv_player dest_player = dv_unit_get_dv_player( dest_unit );
+
+       if( dest_player != NULL && src_player != NULL )
+               dv_player_replace_player( dest_player, src_player );
+
+       return 0;
+}
+
+/** Get the guid associated to this unit.
+*/
+
+octlet_t dv_unit_get_guid( dv_unit unit )
+{
+       return unit->guid;
+}
+
+/** Get the node id associated to this unit.
+*/
+
+int dv_unit_get_nodeid( dv_unit unit )
+{
+       return (unit->node_id & 0x3f);
+}
+
+/** Get the channel associated to this unit.
+*/
+
+int dv_unit_get_channel( dv_unit unit )
+{
+       return (unit->channel);
+}
+
+/** Turn unit online.
+*/
+
+int dv_unit_online( dv_unit unit )
+{
+       int result = 0;
+       int port, node_id;
+       
+       if ( unit->raw1394 != NULL )
+               raw1394_close( unit->raw1394 );
+       
+       node_id = raw1394_find_node( &(unit->raw1394), unit->guid );
+       if ( node_id != -1 )
+       {
+               unit->node_id = 0xffc0 | node_id;       
+               port = dv_unit_get_port( unit );
+       
+               unit->dv1394_fd = open( devices[ port ][ device_count[port] ], O_RDWR );
+               if ( unit->dv1394_fd < 0 )
+               {
+                       dv1394d_log( LOG_ERR, "failed to open dv1394 device - %s\n", devices[ port ][ device_count[port] ] );
+                       dv_unit_close( unit );
+               }
+               else
+               {
+                       device_count[ port ] ++;
+                       if ( establish_p2p_connection( unit->raw1394, unit->node_id, (unsigned int *) &(unit->channel) ) )
+                       {
+                               avc1394_vcr_record( unit->raw1394, unit->node_id );
+                               unit->online = 1;
+                               dv_unit_status_communicate( unit );
+                               result = 1;
+                       }
+               }
+       }
+                               
+       return result;
+}
+
+/** Turn unit offline.
+*/
+
+void dv_unit_offline( dv_unit unit )
+{
+       if ( unit->online == 1 )
+       {
+               if ( unit->is_terminated == 0 )
+                       dv_unit_terminate( unit );
+               unit->online = 0;
+               if ( unit->raw1394 != NULL )
+               {
+                       avc1394_vcr_stop( unit->raw1394, unit->node_id );
+                       break_p2p_connection( unit->raw1394, unit->node_id, unit->channel );
+               }
+               if ( unit->dv1394_fd > -1 )
+               {
+                       close( unit->dv1394_fd );
+                       device_count[ dv_unit_get_port( unit ) ] --;
+               }
+               dv_unit_status_communicate( unit );
+               dv1394d_log( LOG_DEBUG, "Unit with GUID %08x%08x is now offline.",
+                       (quadlet_t) (unit->guid>>32), (quadlet_t) (unit->guid & 0xffffffff) );
+       }
+}
+
+/** Determine if unit is offline.
+*/
+
+int dv_unit_is_offline( dv_unit unit )
+{
+       return (unit->online == 0);
+}
+
+/** Obtain the status for a given unit
+*/
+
+int dv_unit_get_status( dv_unit unit, dv1394_status status )
+{
+       int error = -1;
+
+       memset( status, 0, sizeof( dv1394_status_t ) );
+
+       if ( unit != NULL )
+       {
+               dv_player player = dv_unit_get_dv_player( unit );
+
+               error = 0;
+
+               if ( player != NULL )
+               {
+                       dv_frame head = dv_pump_get_head( player->pump );
+                       dv_frame tail = dv_pump_get_tail( player->pump );
+
+                       status->speed = (int)( dv_player_get_speed( player ) * 1000.0 );
+                       status->fps = dv_player_frames_per_second( player, 0 );
+
+                       if ( head != NULL )
+                       {
+                               dv_frame_id id = dv_frame_get_id( head );
+                               if ( id->resource != NULL )
+                               {
+                                       const char *resource = id->resource;
+                                       if ( resource != NULL && unit->root_dir != NULL )
+                                               resource += strlen( unit->root_dir ) - ( unit->root_dir[ strlen( unit->root_dir ) - 1 ] == '/' );
+                                       strncpy( status->clip, resource, sizeof( status->clip ) );
+                               }
+                               else
+                               {
+                                       char *title = dv_player_get_name( player, dv_player_get_clip_containing( player, 0 ), unit->root_dir );
+                                       if ( title != NULL )
+                                               strncpy( status->clip, title, sizeof( status->clip ) );
+                               }
+
+                               status->position = id->relative;
+                               status->in = id->in;
+                               status->out = id->out;
+                               status->length = id->length;
+                               status->seek_flag = id->seek_flag;
+                       }
+                       else
+                       {
+                               char *title = dv_player_get_name( player, dv_player_get_clip_containing( player, 0 ), unit->root_dir );
+                               if ( title != NULL )
+                                       strncpy( status->clip, title, sizeof( status->clip ) );
+                       }
+
+                       if ( tail != NULL )
+                       {
+                               dv_frame_id id = dv_frame_get_id( tail );
+                               const char *resource = id->resource;
+                               if ( resource != NULL && unit->root_dir != NULL )
+                                       resource += strlen( unit->root_dir ) - ( unit->root_dir[ strlen( unit->root_dir ) - 1 ] == '/' );
+                               if ( resource != NULL )
+                                       strncpy( status->tail_clip, resource, sizeof( status->clip ) );
+                               status->tail_position = id->relative;
+                               status->tail_in = id->in;
+                               status->tail_out = id->out;
+                               status->tail_length = id->length;
+                       }
+                       
+                       status->generation = player->generation;
+                       status->clip_index = dv_unit_get_current_clip( unit );
+               }
+
+               if ( dv_unit_is_offline( unit ) )
+                       status->status = unit_offline;
+               else if ( !strcmp( status->clip, "" ) )
+                       status->status = unit_not_loaded;
+               else if ( dv_unit_has_terminated( unit ) )
+                       status->status = unit_stopped;
+               else if ( status->speed == 0 )
+                       status->status = unit_paused;
+               else
+                       status->status = unit_playing;
+       }
+       else
+       {
+               status->status = unit_undefined;
+       }
+
+       status->unit = unit->unit;
+
+       return error;
+}
+
+/** Change position in the playlist.
+*/
+
+void dv_unit_change_position( dv_unit unit, int clip, long position )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_player_set_clip_position( player, clip, position );
+       dv_unit_status_communicate( unit );
+}
+
+/** Change speed.
+*/
+
+void dv_unit_change_speed( dv_unit unit, int speed )
+{
+       if ( dv_unit_has_terminated( unit ) )
+               dv_unit_change_position( unit, 0, 0 );
+       else
+               dv_unit_play( unit, speed );
+}
+
+int    dv_unit_get_current_clip( dv_unit unit )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       unsigned long position = dv_player_get_position( player );
+       return dv_player_get_clip_containing( player, position );
+}
+
+/** Set a clip's in point
+*/
+
+int dv_unit_set_clip_in( dv_unit unit, int index, long position )
+{
+       int error = 0;
+       dv_player player = dv_unit_get_dv_player( unit );
+
+       if ( player != NULL )
+       {
+               dv_unit_change_speed( unit, 0 );
+               if ( dv_player_set_in_point( player, index, (unsigned long) position ) == position )
+                       dv_player_set_clip_position( player, index, position );
+               else
+                       error = -2;
+       }
+       else
+       {
+               error = -1;
+       }
+
+       dv_unit_status_communicate( unit );
+
+       return error;
+
+}
+
+/** Set a clip's out point.
+*/
+
+int dv_unit_set_clip_out( dv_unit unit, int index, long position )
+{
+       int error = 0;
+       dv_player player = dv_unit_get_dv_player( unit );
+
+       if ( player != NULL )
+       {
+               dv_unit_change_speed( unit, 0 );
+               if ( dv_player_set_out_point( player, index, position ) == position )
+                       dv_player_set_clip_position( player, index, position );
+               else
+                       error = -2;
+       }
+       else
+       {
+               error = -1;
+       }
+
+       dv_unit_status_communicate( unit );
+
+       return error;
+}
+
+/** Step by specified position.
+*/
+
+void dv_unit_step( dv_unit unit, int offset )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_player_change_position( player, dv_seek_relative, offset );
+}
+
+/** Set the unit's clip mode regarding in and out points.
+*/
+
+void dv_unit_set_mode( dv_unit unit, dv_player_clip_mode mode )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       if ( player != NULL )
+               dv_player_set_clip_mode( player, mode );
+       dv_unit_status_communicate( unit );
+}
+
+/** Get the unit's clip mode regarding in and out points.
+*/
+
+dv_player_clip_mode dv_unit_get_mode( dv_unit unit )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       return dv_player_get_clip_mode( player );
+}
+
+/** Set the unit's clip mode regarding eof handling.
+*/
+
+void dv_unit_set_eof_action( dv_unit unit, dv_player_eof_action action )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_player_set_eof_action( player, action );
+       dv_unit_status_communicate( unit );
+}
+
+/** Get the unit's clip mode regarding eof handling.
+*/
+
+dv_player_eof_action dv_unit_get_eof_action( dv_unit unit )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       return dv_player_get_eof_action( player );
+}
+
+/** Release the unit
+
+    \todo error handling
+    \param unit A dv_unit handle.
+*/
+
+void dv_unit_close( dv_unit unit )
+{
+       if ( unit != NULL )
+       {
+               dv1394d_log( LOG_DEBUG, "closing unit..." );
+               dv_unit_offline( unit );
+               if ( unit->pump != NULL )
+               {
+                       dv_pump_terminate( unit->pump );
+                       dv_pump_flush( unit->pump );
+                       dv_pump_return_used_output( unit->pump );
+                       dv_input_join_thread( unit->in );
+                       if ( !unit->is_terminated )
+                               pthread_join( unit->out, NULL );
+                       dv_pump_close( unit->pump );
+                       unit->pump = NULL;
+               }
+               raw1394_close( unit->raw1394 );
+               free( unit );
+               dv1394d_log( LOG_DEBUG, "... unit closed." );
+       }
+}
+
+/** Get the raw1394 port associated to this unit.
+*/
+
+int dv_unit_get_port( dv_unit unit )
+{
+       if ( unit->raw1394 != NULL )
+               return (int) raw1394_get_userdata( unit->raw1394 );
+       else
+               return -1;
+}
+
+/** Set the dv1394 file descriptor for the unit.
+*/
+
+void dv_unit_set_dv1394_fd( dv_unit unit, int fd )
+{
+       unit->dv1394_fd = fd;
+}
+
+/** Get the dv1394 syt_offset (timestamp latency) property.
+*/
+
+unsigned int dv_unit_get_syt_offset( dv_unit unit )
+{
+       return unit->dv1394_syt_offset;
+}
+
+/** Get the dv1394 cip_n (timing numerator) property.
+*/
+
+unsigned int dv_unit_get_cip_n( dv_unit unit )
+{
+       return unit->dv1394_cip_n;
+}
+
+/** Get the dv1394 cip_d (timing denominator) property.
+*/
+
+unsigned int dv_unit_get_cip_d( dv_unit unit )
+{
+       return unit->dv1394_cip_d;
+}
+
+/** Set the dv1394 syt_offset (timestamp latency) property.
+
+    Stops and restarts the unit if playing.
+*/
+
+void dv_unit_set_syt_offset( dv_unit unit, unsigned int syt_offset )
+{
+       int restart = !unit->is_terminated;
+       int speed = (int)( dv_player_get_speed( dv_unit_get_dv_player(unit) ) * 1000.0 );
+       
+       dv_unit_terminate( unit );
+       unit->dv1394_syt_offset = syt_offset;
+       if ( restart )
+               dv_unit_play( unit, speed );
+}
+       
+/** Set the dv1394 cip_n (timing numerator) property.
+
+    Stops and restarts the unit if playing.
+*/
+
+void dv_unit_set_cip_n( dv_unit unit, unsigned int cip_n )
+{
+       int restart = !unit->is_terminated;
+       int speed = (int)( dv_player_get_speed( dv_unit_get_dv_player(unit) ) * 1000.0 );
+       
+       dv_unit_terminate( unit );
+       unit->dv1394_cip_n = cip_n;
+       if ( restart )
+               dv_unit_play( unit, speed );
+}
+
+/** Set the dv1394 cip_d (timing denominator) property.
+
+    Stops and restarts the unit if playing.
+*/
+
+void dv_unit_set_cip_d( dv_unit unit, unsigned int cip_d )
+{
+       int restart = !unit->is_terminated;
+       int speed = (int)( dv_player_get_speed( dv_unit_get_dv_player(unit) ) * 1000.0 );
+       
+       dv_unit_terminate( unit );
+       unit->dv1394_cip_d = cip_d;
+       if ( restart )
+               dv_unit_play( unit, speed );
+}
+
+/** Terminate, but only the output thread and close dv1394.
+*/
+
+void dv_unit_suspend( dv_unit unit )
+{
+       if ( unit->is_terminated == 0 )
+       {
+               unit->is_terminated = 1;
+               unit->is_suspended = 1;
+               dv_pump_terminate( unit->pump );
+               dv_pump_flush( unit->pump );
+               pthread_cancel( unit->out );
+       }
+       if ( unit->dv1394_fd > -1 )
+       {
+               close( unit->dv1394_fd );
+               device_count[ dv_unit_get_port( unit ) ] --;
+       }
+       unit->dv1394_fd = -1;
+       dv_unit_status_communicate( unit );
+}
+
+
+/** Restore unit on the bus, re-open dv1394, start playback if pump is running.
+*/
+
+void dv_unit_restore( dv_unit unit )
+{
+       int result = 0;
+       int port, node_id;
+       
+       if ( unit->raw1394 != NULL )
+               raw1394_close( unit->raw1394 );
+       
+       node_id = raw1394_find_node( &(unit->raw1394), unit->guid );
+       if ( node_id != -1 )
+       {
+               unit->node_id = 0xffc0 | node_id;       
+               port = dv_unit_get_port( unit );
+       
+               unit->dv1394_fd = open( devices[ port ][ device_count[port] ], O_RDWR );
+               if ( unit->dv1394_fd < 0 )
+               {
+                       dv1394d_log( LOG_ERR, "failed to open dv1394 device - %s\n", devices[ port ][ device_count[port] ] );
+                       dv_unit_close( unit );
+               }
+               else
+               {
+                       device_count[ port ] ++;
+                       break_p2p_connection( unit->raw1394, unit->node_id, unit->channel );
+                       if ( establish_p2p_connection( unit->raw1394, unit->node_id, (unsigned int *) &(unit->channel) ) )
+                       {
+                               avc1394_vcr_record( unit->raw1394, unit->node_id );
+                               unit->online = 1;
+                               result = 1;
+                       }
+               }
+       }
+       if ( unit->is_suspended == 1 )
+       {
+               int retval;
+               dv_frame frame = dv_pump_get_available_output( unit->pump );
+               struct dv1394_init setup =
+               {
+                       api_version: DV1394_API_VERSION,
+                       channel: unit->channel,
+                       /* this only sets the *requested* size of the ringbuffer,
+                          in frames */ 
+                       n_frames: unit->n_frames,
+                       format: dv_frame_is_pal(frame) ? DV1394_PAL : DV1394_NTSC,
+                       cip_n: unit->dv1394_cip_n,
+                       cip_d: unit->dv1394_cip_d,
+                       syt_offset: unit->dv1394_syt_offset
+               };
+               pthread_attr_t attr;
+
+               dv_input_join_thread( unit->in );
+               unit->is_terminated = 0;
+               unit->is_suspended = 0;
+               dv_pump_restart( unit->pump );
+               dv_input_start_thread( unit->in );
+               
+               /* initialize dv1394 */
+               retval = ioctl( unit->dv1394_fd, DV1394_INIT, &setup );
+               if ( retval < 0 )
+                       return;
+               
+               pthread_attr_init( &attr );
+               pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
+               pthread_attr_setinheritsched( &attr, PTHREAD_INHERIT_SCHED );
+               /* pthread_attr_setschedpolicy( &attr, SCHED_RR ); */
+               pthread_create( &unit->out, &attr, output, unit );
+       }
+       dv_unit_status_communicate( unit );
+}
diff --git a/mlt/src/miracle/miracle_unit.h b/mlt/src/miracle/miracle_unit.h
new file mode 100644 (file)
index 0000000..5433818
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * dvunit.h -- DV Transmission Unit Header
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DV_UNIT_H_
+#define _DV_UNIT_H_
+
+#include <pthread.h>
+#include <libraw1394/raw1394.h>
+
+#include <dv1394notifier.h>
+#include <dv1394status.h>
+#include <dvpump.h>
+#include <dvplayer.h>
+#include <dvinput.h>
+#include <dverror.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct
+{
+       int        unit;
+       dv_pump    pump;
+       dv_player  player;
+       dv_input   in;
+       int                dv1394_fd;
+       int        is_terminated;
+       int        is_suspended;
+       pthread_t  out;
+       int                channel;
+       nodeid_t   node_id;
+       octlet_t   guid;
+       raw1394handle_t raw1394;
+       int        allow_stdin;
+       int        buffer_size;
+       int        online;
+       dv1394_notifier notifier;
+       char      *root_dir;
+       unsigned int dv1394_syt_offset;
+       unsigned int dv1394_cip_n;
+       unsigned int dv1394_cip_d;
+       unsigned int n_frames;
+       unsigned int n_fill;
+       uint8_t *mmap;
+       int mmap_pos;
+       int mmap_length;
+} dv_unit_t, *dv_unit;
+
+extern dv_unit              dv_unit_init( octlet_t guid, int channel );
+extern void                 dv_unit_allow_stdin( dv_unit unit, int flag );
+extern void                 dv_unit_set_buffer_size( dv_unit unit, int size );
+extern int                  dv_unit_get_buffer_size( dv_unit unit );
+extern void                 dv_unit_set_n_frames( dv_unit unit, int size );
+extern int                                     dv_unit_get_n_frames( dv_unit unit );
+extern void                 dv_unit_set_n_fill( dv_unit unit, int size );
+extern int                                     dv_unit_get_n_fill( dv_unit unit );
+extern dv_error_code        dv_unit_load( dv_unit unit, const char *clip, long in, long out, int flush );
+extern dv_error_code           dv_unit_insert( dv_unit unit, const char *clip, int index, long in, long out );
+extern dv_error_code        dv_unit_append( dv_unit unit, const char *clip, long in, long out );
+extern dv_error_code           dv_unit_remove( dv_unit unit, int index );
+extern dv_error_code           dv_unit_clean( dv_unit unit );
+extern dv_error_code           dv_unit_move( dv_unit unit, int src, int dest );
+extern int                  dv_unit_transfer( dv_unit dest_unit, dv_unit src_unit );
+extern void                 dv_unit_play( dv_unit_t *unit, int speed );
+extern void                 dv_unit_terminate( dv_unit );
+extern int                  dv_unit_has_terminated( dv_unit );
+extern octlet_t             dv_unit_get_guid( dv_unit unit );
+extern int                  dv_unit_get_nodeid( dv_unit unit );
+extern int                  dv_unit_get_channel( dv_unit unit );
+extern int                  dv_unit_online( dv_unit unit );
+extern void                 dv_unit_offline( dv_unit unit );
+extern int                  dv_unit_is_offline( dv_unit unit );
+extern void                 dv_unit_set_notifier( dv_unit, dv1394_notifier, char * );
+extern int                  dv_unit_get_status( dv_unit, dv1394_status );
+extern void                 dv_unit_change_position( dv_unit, int, long position );
+extern void                 dv_unit_change_speed( dv_unit unit, int speed );
+extern int                  dv_unit_set_clip_in( dv_unit unit, int index, long position );
+extern int                  dv_unit_set_clip_out( dv_unit unit, int index, long position );
+extern void                 dv_unit_set_mode( dv_unit unit, dv_player_clip_mode mode );
+extern dv_player_clip_mode  dv_unit_get_mode( dv_unit unit );
+extern void                 dv_unit_set_eof_action( dv_unit unit, dv_player_eof_action mode );
+extern dv_player_eof_action dv_unit_get_eof_action( dv_unit unit );
+extern void                 dv_unit_step( dv_unit unit, int offset );
+extern void                 dv_unit_close( dv_unit unit );
+extern int                  dv_unit_get_port( dv_unit unit );
+extern void                 dv_unit_set_dv1394_fd( dv_unit unit, int fd );
+extern unsigned int         dv_unit_get_syt_offset( dv_unit unit );
+extern unsigned int         dv_unit_get_cip_n( dv_unit unit );
+extern unsigned int         dv_unit_get_cip_d( dv_unit unit );
+extern void                 dv_unit_set_syt_offset( dv_unit unit, unsigned int );
+extern void                 dv_unit_set_cip_n( dv_unit unit, unsigned int );
+extern void                 dv_unit_set_cip_d( dv_unit unit, unsigned int );
+extern void                 dv_unit_suspend( dv_unit );
+extern void                 dv_unit_restore( dv_unit );
+extern dv_player                       dv_unit_get_dv_player( dv_unit );
+extern int                                     dv_unit_get_current_clip( dv_unit );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/miracle/miracle_unit_commands.c b/mlt/src/miracle/miracle_unit_commands.c
new file mode 100644 (file)
index 0000000..b12f2c7
--- /dev/null
@@ -0,0 +1,612 @@
+/*
+ * unit_commands.c
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "dvunit.h"
+#include "global_commands.h"
+#include "dverror.h"
+#include "dvframepool.h"
+#include "log.h"
+
+int dv1394d_load( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       char *filename = (char*) cmd_arg->argument;
+       char fullname[1024];
+       int flush = 1;
+
+       if ( filename[0] == '!' )
+       {
+               flush = 0;
+               filename ++;
+       }
+
+       if ( filename[0] == '/' )
+               filename++;
+
+       snprintf( fullname, 1023, "%s%s", cmd_arg->root_dir, filename );
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               long in = -1, out = -1;
+               if ( dv_tokeniser_count( cmd_arg->tokeniser ) == 5 )
+               {
+                       in = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 3 ) );
+                       out = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 4 ) );
+               }
+               if ( dv_unit_load( unit, fullname, in, out, flush ) != dv_pump_ok )
+                       return RESPONSE_BAD_FILE;
+       }
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_list( command_argument cmd_arg )
+{
+       int i = 0;
+       dv_unit unit = dv1394d_get_unit( cmd_arg->unit );
+       dv_player player = dv_unit_get_dv_player( unit );
+       
+       if ( player != NULL )
+       {
+               dv_response_printf( cmd_arg->response, 1024, "%d\n", player->generation );
+               
+               for ( i = 0; i < dv_player_get_clip_count( player ); i ++ )
+               {
+                       dv_clip clip = dv_player_get_clip( player, i );
+                       
+                       dv_response_printf( cmd_arg->response, 10240,
+                                                               "%d \"%s\" %d %d %d %d %.2f\n", 
+                                                               i,
+                                                               dv_clip_get_resource( clip, cmd_arg->root_dir ),
+                                                               dv_clip_get_in( clip ),
+                                                               ( !dv_clip_is_seekable( clip ) && clip->out_frame == -1 ? -1 : dv_clip_get_out( clip ) ),
+                                                               dv_clip_get_max_frames( clip ),
+                                                               ( !dv_clip_is_seekable( clip ) && clip->out_frame == -1 ? -1 : dv_player_get_length_of_clip( player, i ) ),
+                                                               dv_clip_frames_per_second( clip ) );
+               }
+       
+               dv_response_printf( cmd_arg->response, 2, "\n" );
+               
+               return RESPONSE_SUCCESS;
+       }
+       return RESPONSE_INVALID_UNIT;
+}
+
+static int parse_clip( command_argument cmd_arg, int arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       int clip = dv_unit_get_current_clip( unit );
+       
+       if ( dv_tokeniser_count( cmd_arg->tokeniser ) > arg )
+       {
+               dv_player player = dv_unit_get_dv_player( unit );
+               char *token = dv_tokeniser_get_string( cmd_arg->tokeniser, arg );
+               if ( token[ 0 ] == '+' )
+                       clip += atoi( token + 1 );
+               else if ( token[ 0 ] == '-' )
+                       clip -= atoi( token + 1 );
+               else
+                       clip = atoi( token );
+               if ( clip < 0 )
+                       clip = 0;
+               if ( clip >= player->size )
+                       clip = player->size - 1;
+       }
+       
+       return clip;
+}
+
+int dv1394d_insert( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       char *filename = (char*) cmd_arg->argument;
+       char fullname[1024];
+
+       if ( filename[0] == '/' )
+               filename++;
+
+       snprintf( fullname, 1023, "%s%s", cmd_arg->root_dir, filename );
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               long in = -1, out = -1;
+               int index = parse_clip( cmd_arg, 3 );
+               
+               if ( dv_tokeniser_count( cmd_arg->tokeniser ) == 6 )
+               {
+                       in = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 4 ) );
+                       out = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 5 ) );
+               }
+               
+               switch( dv_unit_insert( unit, fullname, index, in, out ) )
+               {
+                       case dv_pump_ok:
+                               return RESPONSE_SUCCESS;
+                       case dv_pump_too_many_files_open:
+                               return RESPONSE_TOO_MANY_FILES;
+                       default:
+                               return RESPONSE_BAD_FILE;
+               }
+       }
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_remove( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               int index = parse_clip( cmd_arg, 2 );
+                       
+               if ( dv_unit_remove( unit, index ) != dv_pump_ok )
+                       return RESPONSE_BAD_FILE;
+       }
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_clean( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               if ( dv_unit_clean( unit ) != dv_pump_ok )
+                       return RESPONSE_BAD_FILE;
+       }
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_move( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if ( unit != NULL )
+       {
+               if ( dv_tokeniser_count( cmd_arg->tokeniser ) > 2 )
+               {
+                       int src = parse_clip( cmd_arg, 2 );
+                       int dest = parse_clip( cmd_arg, 3 );
+                       
+                       if ( dv_unit_move( unit, src, dest ) != dv_pump_ok )
+                               return RESPONSE_BAD_FILE;
+               }
+               else
+               {
+                       return RESPONSE_MISSING_ARG;
+               }
+       }
+       else
+       {
+               return RESPONSE_INVALID_UNIT;
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_append( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       char *filename = (char*) cmd_arg->argument;
+       char fullname[1024];
+
+       if ( filename[0] == '/' )
+               filename++;
+       snprintf( fullname, 1023, "%s%s", cmd_arg->root_dir, filename );
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               long in = -1, out = -1;
+               if ( dv_tokeniser_count( cmd_arg->tokeniser ) == 5 )
+               {
+                       in = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 3 ) );
+                       out = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 4 ) );
+               }
+               switch ( dv_unit_append( unit, fullname, in, out ) )
+               {
+                       case dv_pump_ok:
+                               return RESPONSE_SUCCESS;
+                       case dv_pump_too_many_files_open:
+                               return RESPONSE_TOO_MANY_FILES;
+                       default:
+                               return RESPONSE_BAD_FILE;
+               }
+       }
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_play( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               int speed = 1000;
+               if ( dv_tokeniser_count( cmd_arg->tokeniser ) == 3 )
+                       speed = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 2 ) );
+               dv_unit_play( unit, speed );
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_stop( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+               dv_unit_terminate( unit );
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_pause( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else 
+               dv_unit_play( unit, 0 );
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_rewind( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+               dv_unit_change_speed( unit, -2000 );
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_step( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               dv_unit_play( unit, 0 );
+               dv_unit_step( unit, *(int*) cmd_arg->argument );
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_goto( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       int clip = parse_clip( cmd_arg, 3 );
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+               dv_unit_change_position( unit, clip, *(int*) cmd_arg->argument );
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_ff( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+               dv_unit_change_speed( unit, 2000 );
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_set_in_point( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       int clip = parse_clip( cmd_arg, 3 );
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               int position = *(int *) cmd_arg->argument;
+
+               switch( dv_unit_set_clip_in( unit, clip, position ) )
+               {
+                       case -1:
+                               return RESPONSE_BAD_FILE;
+                       case -2:
+                               return RESPONSE_OUT_OF_RANGE;
+               }
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_set_out_point( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       int clip = parse_clip( cmd_arg, 3 );
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               int position = *(int *) cmd_arg->argument;
+
+               switch( dv_unit_set_clip_out( unit, clip, position ) )
+               {
+                       case -1:
+                               return RESPONSE_BAD_FILE;
+                       case -2:
+                               return RESPONSE_OUT_OF_RANGE;
+               }
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_get_unit_status( command_argument cmd_arg )
+{
+       dv1394_status_t status;
+       int error = dv_unit_get_status( dv1394d_get_unit( cmd_arg->unit ), &status );
+
+       if ( error == -1 )
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               char text[ 10240 ];
+
+               dv_response_printf( cmd_arg->response, 
+                                                       sizeof( text ), 
+                                                       dv1394_status_serialise( &status, text, sizeof( text ) ) );
+
+               return RESPONSE_SUCCESS_1;
+       }
+       
+       return 0;
+}
+
+
+int dv1394d_set_unit_property( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               char *key = (char*) cmd_arg->argument;
+               char *value = NULL;
+
+               value = strchr( key, '=' );
+               if (value == NULL)
+                       return RESPONSE_OUT_OF_RANGE;
+               value[0] = 0;
+               value++;
+               dv1394d_log( LOG_DEBUG, "USET %s = %s", key, value );
+               if ( strncasecmp( key, "eof", 1024) == 0 )
+               {
+                       if ( strncasecmp( value, "pause", 1024) == 0)
+                               dv_unit_set_eof_action( unit, dv_player_pause );
+                       else if ( strncasecmp( value, "loop", 1024) == 0)
+                               dv_unit_set_eof_action( unit, dv_player_loop );
+                       else if ( strncasecmp( value, "stop", 1024) == 0)
+                               dv_unit_set_eof_action( unit, dv_player_terminate );
+                       else if ( strncasecmp( value, "clean", 1024) == 0)
+                               dv_unit_set_eof_action( unit, dv_player_clean_loop );
+                       else
+                               return RESPONSE_OUT_OF_RANGE;
+               }
+               else if ( strncasecmp( key, "points", 1024) == 0 )
+               {
+                       if ( strncasecmp( value, "use", 1024) == 0)
+                               dv_unit_set_mode( unit, dv_clip_mode_restricted );
+                       else if ( strncasecmp( value, "ignore", 1024) == 0)
+                               dv_unit_set_mode( unit, dv_clip_mode_unrestricted );
+                       else
+                               return RESPONSE_OUT_OF_RANGE;
+               }
+               else if ( strncasecmp( key, "syt_offset", 1024) == 0 )
+               {
+                       dv_unit_set_syt_offset( unit, atoi( value ) );
+               }
+               else if ( strncasecmp( key, "cip_n", 1024) == 0 )
+               {
+                       dv_unit_set_cip_n( unit, atoi( value ) );
+               }
+               else if ( strncasecmp( key, "cip_d", 1024) == 0 )
+               {
+                       dv_unit_set_cip_d( unit, atoi( value ) );
+               }
+               else if ( strncasecmp( key, "size", 1024) == 0 )
+               {
+                       dv_unit_set_buffer_size( unit, atoi( value ) );
+               }
+               else if ( strncasecmp( key, "n_frames", 1024) == 0 )
+               {
+                       dv_unit_set_n_frames( unit, atoi( value ) );
+               }               
+               else if ( strncasecmp( key, "n_fill", 1024) == 0 )
+               {
+                       dv_unit_set_n_fill( unit, atoi( value ) );
+               }               
+               else
+                       return RESPONSE_OUT_OF_RANGE;
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_get_unit_property( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               char *key = (char*) cmd_arg->argument;
+
+               if ( strncasecmp( key, "eof", 1024) == 0 )
+               {
+                       switch ( dv_unit_get_eof_action( unit ) )
+                       {
+                               case dv_player_pause:
+                                       dv_response_write( cmd_arg->response, "pause", strlen("pause") );
+                                       break;
+                               case dv_player_loop:
+                                       dv_response_write( cmd_arg->response, "loop", strlen("loop") );
+                                       break;
+                               case dv_player_terminate:
+                                       dv_response_write( cmd_arg->response, "stop", strlen("stop") );
+                                       break;
+                               case dv_player_clean_loop:
+                                       dv_response_write( cmd_arg->response, "clean", strlen("clean") );
+                                       break;
+                       }
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "points", 1024) == 0 )
+               {
+                       if ( dv_unit_get_mode( unit ) == dv_clip_mode_restricted )
+                               dv_response_write( cmd_arg->response, "use", strlen("use") );
+                       else
+                               dv_response_write( cmd_arg->response, "ignore", strlen("ignore") );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "syt_offset", 1024) == 0 )
+               {
+                       dv_response_printf( cmd_arg->response, 1024, "%d\n",
+                               dv_unit_get_syt_offset( unit ) );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "cip_n", 1024) == 0 )
+               {
+                       dv_response_printf( cmd_arg->response, 1024, "%d\n",
+                               dv_unit_get_cip_n( unit ) );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "cip_d", 1024) == 0 )
+               {
+                       dv_response_printf( cmd_arg->response, 1024, "%d\n",
+                               dv_unit_get_cip_d( unit ) );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "size", 1024) == 0 )
+               {
+                       dv_response_printf( cmd_arg->response, 1024, "%d\n",
+                               dv_unit_get_buffer_size( unit ) );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "n_frames", 1024) == 0 )
+               {
+                       dv_response_printf( cmd_arg->response, 1024, "%d\n",
+                               dv_unit_get_n_frames( unit ) );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "n_fill", 1024) == 0 )
+               {
+                       dv_response_printf( cmd_arg->response, 1024, "%d\n",
+                               dv_unit_get_n_fill( unit ) );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "all", 1024 ) == 0 )
+               {
+                       switch ( dv_unit_get_eof_action( unit ) )
+                       {
+                               case dv_player_pause:
+                                       dv_response_write( cmd_arg->response, "eof=pause\n", strlen("pause") );
+                                       break;
+                               case dv_player_loop:
+                                       dv_response_write( cmd_arg->response, "eof=loop\n", strlen("loop") );
+                                       break;
+                               case dv_player_terminate:
+                                       dv_response_write( cmd_arg->response, "eof=stop\n", strlen("stop") );
+                                       break;
+                               case dv_player_clean_loop:
+                                       dv_response_write( cmd_arg->response, "eof=clean\n", strlen("clean") );
+                                       break;
+                       }
+                       if ( dv_unit_get_mode( unit ) == dv_clip_mode_restricted )
+                               dv_response_write( cmd_arg->response, "points=use\n", strlen("use") );
+                       else
+                               dv_response_write( cmd_arg->response, "points=ignore\n", strlen("ignore") );
+                       dv_response_printf( cmd_arg->response, 1024, "syt_offset=%d\n", dv_unit_get_syt_offset( unit ) );
+                       dv_response_printf( cmd_arg->response, 1024, "cip_n=%d\n", dv_unit_get_cip_n( unit ) );
+                       dv_response_printf( cmd_arg->response, 1024, "cip_d=%d\n", dv_unit_get_cip_d( unit ) );
+                       dv_response_printf( cmd_arg->response, 1024, "size=%d\n", dv_unit_get_buffer_size( unit ) );
+                       dv_response_printf( cmd_arg->response, 1024, "n_frames=%d\n", dv_unit_get_n_frames( unit ) );
+                       dv_response_printf( cmd_arg->response, 1024, "n_fill=%d\n", dv_unit_get_n_fill( unit ) );
+               }
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+
+int dv1394d_transfer( command_argument cmd_arg )
+{
+       dv_unit src_unit = dv1394d_get_unit(cmd_arg->unit);
+       int dest_unit_id = -1;
+       char *string = (char*) cmd_arg->argument;
+       if ( string != NULL && ( string[ 0 ] == 'U' || string[ 0 ] == 'u' ) && strlen( string ) > 1 )
+               dest_unit_id = atoi( string + 1 );
+       
+       if ( src_unit != NULL && dest_unit_id != -1 )
+       {
+               dv_unit dest_unit = dv1394d_get_unit( dest_unit_id );
+               if ( dest_unit != NULL && !dv_unit_is_offline(dest_unit) && dest_unit != src_unit )
+               {
+                       dv_unit_transfer( dest_unit, src_unit );
+                       return RESPONSE_SUCCESS;
+               }
+       }
+       
+       return RESPONSE_INVALID_UNIT;
+}
diff --git a/mlt/src/miracle/miracle_unit_commands.h b/mlt/src/miracle/miracle_unit_commands.h
new file mode 100644 (file)
index 0000000..a7163bd
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * unit_commands.h
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef _UNIT_COMMANDS_H_
+#define _UNIT_COMMANDS_H_
+
+#include "dvconnection.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+extern response_codes dv1394d_list( command_argument );
+extern response_codes dv1394d_load( command_argument );
+extern response_codes dv1394d_insert( command_argument );
+extern response_codes dv1394d_remove( command_argument );
+extern response_codes dv1394d_clean( command_argument );
+extern response_codes dv1394d_move( command_argument );
+extern response_codes dv1394d_append( command_argument );
+extern response_codes dv1394d_play( command_argument );
+extern response_codes dv1394d_stop( command_argument );
+extern response_codes dv1394d_pause( command_argument );
+extern response_codes dv1394d_rewind( command_argument );
+extern response_codes dv1394d_step( command_argument );
+extern response_codes dv1394d_goto( command_argument );
+extern response_codes dv1394d_ff( command_argument );
+extern response_codes dv1394d_set_in_point( command_argument );
+extern response_codes dv1394d_set_out_point( command_argument );
+extern response_codes dv1394d_get_unit_status( command_argument );
+extern response_codes dv1394d_set_unit_property( command_argument );
+extern response_codes dv1394d_get_unit_property( command_argument );
+extern response_codes dv1394d_transfer( command_argument );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/modules/Makefile b/mlt/src/modules/Makefile
new file mode 100644 (file)
index 0000000..0a4c717
--- /dev/null
@@ -0,0 +1,15 @@
+SUBDIRS = core gtk2 dv sdl # bluefish mcmpeg
+
+all clean depend install:
+       list='$(SUBDIRS)'; \
+       for subdir in $$list; do \
+               [ ! -f disable-$$subdir ] && $(MAKE) -C $$subdir $@; \
+       done
+
+dist-clean:
+       rm -f consumers.dat filters.dat producers.dat transitions.dat; \
+       list='$(SUBDIRS)'; \
+       for subdir in $$list; do \
+               [ ! -f disable-$$subdir ] && $(MAKE) -C $$subdir $@; \
+       done
+
diff --git a/mlt/src/modules/configure b/mlt/src/modules/configure
new file mode 100755 (executable)
index 0000000..365fe43
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Clean up disables if not in help mode
+[ "$help" != "1" ] && rm -f disable-* producers.dat filters.dat transitions.dat consumers.dat
+
+# Iterate through arguments
+for i in $*
+do
+       case $i in
+               --disable-* )   touch disable-${i#--disable-} ;;
+       esac
+done
+
+# Iterate through each of the components
+for i in *
+do
+       if [ -x $i/configure -a \( "$help" = "1" -o ! -f disable-$i \) ]
+       then
+               echo "Configuring $i:"
+               pushd $i > /dev/null
+               ./configure $@
+               [ $? != 0 ] && exit 1
+               popd > /dev/null
+       fi
+done
+
diff --git a/mlt/src/modules/dv/Makefile b/mlt/src/modules/dv/Makefile
new file mode 100644 (file)
index 0000000..22d999e
--- /dev/null
@@ -0,0 +1,29 @@
+
+TARGET = factory.o \
+                libmltdv.so
+
+OBJS = producer_libdv.o 
+
+CFLAGS=-I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread
+
+LDFLAGS=-ldv -lpthread
+
+SRCS := $(OBJS:.o=.c)
+
+all:   $(TARGET)
+
+$(TARGET): $(OBJS)
+               $(CC) -shared -o $@ $(OBJS) $(LDFLAGS)
+
+depend:        $(SRCS)
+               $(CC) -MM $(CFLAGS) $^ 1>.depend
+
+dist-clean:    clean
+               rm -f .depend
+
+clean: 
+               rm -f $(OBJS) $(TARGET)
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/mlt/src/modules/dv/configure b/mlt/src/modules/dv/configure
new file mode 100755 (executable)
index 0000000..876897c
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+if [ "$help" != "1" ]
+then
+
+cat << EOF >> ../producers.dat
+libdv                  libmltdv.so
+EOF
+
+fi
+
diff --git a/mlt/src/modules/dv/factory.c b/mlt/src/modules/dv/factory.c
new file mode 100644 (file)
index 0000000..e27510a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * factory.c -- the factory method interfaces
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "producer_libdv.h"
+
+void *mlt_create_producer( char *id, void *arg )
+{
+       if ( !strcmp( id, "libdv" ) )
+               return producer_libdv_init( arg );
+       return NULL;
+}
+
+void *mlt_create_filter( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_transition( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_consumer( char *id, void *arg )
+{
+       return NULL;
+}
+
diff --git a/mlt/src/modules/dv/producer_libdv.c b/mlt/src/modules/dv/producer_libdv.c
new file mode 100644 (file)
index 0000000..5d2c768
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * producer_libdv.c -- simple libdv test case
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "producer_libdv.h"
+#include <framework/mlt_frame.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <libdv/dv.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+typedef struct producer_libdv_s *producer_libdv;
+
+struct producer_libdv_s
+{
+       struct mlt_producer_s parent;
+       int fd;
+       dv_decoder_t *dv_decoder;
+       int is_pal;
+       uint64_t file_size;
+       int frame_size;
+       long frames_in_file;
+};
+
+static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index );
+static void producer_close( mlt_producer parent );
+
+static int producer_collect_info( producer_libdv this );
+
+mlt_producer producer_libdv_init( char *filename )
+{
+       producer_libdv this = calloc( sizeof( struct producer_libdv_s ), 1 );
+
+       if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 )
+       {
+               mlt_producer producer = &this->parent;
+
+               // Register transport implementation with the producer
+               producer->close = producer_close;
+
+               // Register our get_frame implementation with the producer
+               producer->get_frame = producer_get_frame;
+
+               // Create the dv_decoder
+               this->dv_decoder = dv_decoder_new( FALSE, FALSE, FALSE );
+               this->dv_decoder->quality = DV_QUALITY_BEST;
+               this->dv_decoder->audio->arg_audio_emphasis = 2;
+               dv_set_audio_correction( this->dv_decoder, DV_AUDIO_CORRECT_AVERAGE );
+
+               // Open the file if specified
+               if ( filename != NULL )
+               {
+                       this->fd = open( filename, O_RDONLY );
+                       producer_collect_info( this );
+               }
+
+               // Return the producer
+               return producer;
+       }
+       free( this );
+       return NULL;
+}
+
+static int read_frame( int fd, uint8_t* frame_buf, int *isPAL )
+{
+       int result = read( fd, frame_buf, frame_size_525_60 ) == frame_size_525_60;
+       if ( result )
+       {
+               *isPAL = ( frame_buf[3] & 0x80 );
+
+               if ( *isPAL )
+               {
+                       int diff = frame_size_625_50 - frame_size_525_60;
+                       result = read( fd, frame_buf + frame_size_525_60, diff ) == diff;
+               }
+       }
+       
+       return result;
+}
+
+static int producer_collect_info( producer_libdv this )
+{
+       int valid = 0;
+       uint8_t *dv_data = malloc( frame_size_625_50 );
+
+       if ( dv_data != NULL )
+       {
+               // Read the first frame
+               valid = read_frame( this->fd, dv_data, &this->is_pal );
+
+               // If it looks like a valid frame, the get stats
+               if ( valid )
+               {
+                       // Get the properties
+                       mlt_properties properties = mlt_producer_properties( &this->parent );
+
+                       // Determine the file size
+                       struct stat buf;
+                       fstat( this->fd, &buf );
+
+                       // Store the file size
+                       this->file_size = buf.st_size;
+
+                       // Determine the frame size
+                       this->frame_size = this->is_pal ? frame_size_625_50 : frame_size_525_60;
+
+                       // Determine the number of frames in the file
+                       this->frames_in_file = this->file_size / this->frame_size;
+
+                       // Calculate default in/out points
+                       double fps = this->is_pal ? 25 : 30000 / 1001;
+                       mlt_timecode length = ( mlt_timecode )( this->frames_in_file ) / fps;
+                       mlt_properties_set_double( properties, "fps", fps );
+                       mlt_properties_set_timecode( properties, "playtime", length );
+                       mlt_properties_set_timecode( properties, "length", length );
+                       mlt_properties_set_timecode( properties, "in", 0.0 );
+                       mlt_properties_set_timecode( properties, "out", length );
+
+                       // Set the speed to normal
+                       mlt_properties_set_double( properties, "speed", 1 );
+               }
+
+               free( dv_data );
+       }
+
+       return valid;
+}
+
+#if 0
+static int mc_producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
+{
+       // Get the frames properties
+       mlt_properties properties = mlt_frame_properties( this );
+
+       // Get the dv data
+       uint8_t *dv_data = mlt_properties_get_data( properties, "dv_data", NULL );
+
+       // Determine bytes in frame
+       int bytes_in_frame = dv_data[ 3 ] & 0x80 ? frame_size_625_50 : frame_size_525_60;
+
+       // Assign width and height from properties
+       *width = mlt_properties_get_int( properties, "width" );
+       *height = mlt_properties_get_int( properties, "height" );
+
+       if ( *format == mlt_image_yuv422 )
+       {
+               // Allocate image
+               *buffer = malloc( *width * *height * 2 );
+
+               // Decompress
+               DecompressBuffer_DV( dv_data, bytes_in_frame, *buffer, *width * 2, *width, *height, 0, FOURCC_YUYV, 0, NULL );
+
+               // Set the image on the properties
+               mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, free, NULL );
+       }
+       else
+       {
+               // Allocate image
+               *buffer = malloc( *width * *height * 3 );
+
+               // Decompress
+               DecompressBuffer_DV( dv_data, bytes_in_frame, *buffer, *width * 3, *width, *height, 0, FOURCC_R24C, 0, NULL );
+
+               // Set the image on the properties
+               mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, free, NULL );
+       }
+
+       return 0;
+}
+#endif
+
+static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
+{
+       int pitches[3] = { 0, 0, 0 };
+       uint8_t *pixels[3] = { NULL, NULL, NULL };
+       
+       // Get the frames properties
+       mlt_properties properties = mlt_frame_properties( this );
+
+       // Get the dv decoder
+       dv_decoder_t *decoder = mlt_properties_get_data( properties, "dv_decoder", NULL );
+
+       // Get the dv data
+       uint8_t *dv_data = mlt_properties_get_data( properties, "dv_data", NULL );
+
+       // Assign width and height from properties
+       *width = mlt_properties_get_int( properties, "width" );
+       *height = mlt_properties_get_int( properties, "height" );
+
+       // Parse the header
+       dv_parse_header( decoder, dv_data );
+
+       // Extract an image of the format requested
+       if ( *format == mlt_image_yuv422 )
+       {
+               // Allocate an image
+               uint8_t *image = malloc( *width * *height * 2 );
+
+               // Pass to properties for clean up
+               mlt_properties_set_data( properties, "image", image, *width * *height * 2, free, NULL );
+
+               // Decode the image
+               pitches[ 0 ] = *width * 2;
+               pixels[ 0 ] = image;
+               dv_decode_full_frame( decoder, dv_data, e_dv_color_yuv, pixels, pitches );
+
+               // Assign result
+               *buffer = image;
+       }
+       else if ( *format == mlt_image_rgb24 )
+       {
+               // Allocate an image
+               uint8_t *image = malloc( *width * *height * 3 );
+
+               // Pass to properties for clean up
+               mlt_properties_set_data( properties, "image", image, *width * *height * 3, free, NULL );
+
+               // Decode the frame
+               pitches[ 0 ] = 720 * 3;
+               pixels[ 0 ] = image;
+               dv_decode_full_frame( decoder, dv_data, e_dv_color_rgb, pixels, pitches );
+
+               // Assign result
+               *buffer = image;
+       }
+
+       return 0;
+}
+
+static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
+{
+       int16_t *p;
+       int i, j;
+       int16_t *audio_channels[ 4 ];
+       
+       // Get the frames properties
+       mlt_properties properties = mlt_frame_properties( this );
+
+       // Get the dv decoder
+       dv_decoder_t *decoder = mlt_properties_get_data( properties, "dv_decoder", NULL );
+
+       // Get the dv data
+       uint8_t *dv_data = mlt_properties_get_data( properties, "dv_data", NULL );
+
+       // Parse the header for meta info
+       dv_parse_header( decoder, dv_data );
+
+       // Obtain required values
+       *frequency = decoder->audio->frequency;
+       *samples = decoder->audio->samples_this_frame;
+       *channels = decoder->audio->num_channels;
+
+       // Create a temporary workspace
+       for ( i = 0; i < 4; i++ )
+               audio_channels[ i ] = malloc( DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ) );
+
+       // Create a workspace for the result
+       *buffer = malloc( *channels * DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ) );
+
+       // Pass the allocated audio buffer as a property
+       mlt_properties_set_data( properties, "audio", *buffer, *channels * DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ), free, NULL );
+
+       // Decode the audio
+       dv_decode_full_audio( decoder, dv_data, audio_channels );
+       
+       // Interleave the audio
+       p = *buffer;
+       for ( i = 0; i < *samples; i++ )
+               for ( j = 0; j < *channels; j++ )
+                       *p++ = audio_channels[ j ][ i ];
+
+       // Free the temporary work space
+       for ( i = 0; i < 4; i++ )
+               free( audio_channels[ i ] );
+
+       return 0;
+}
+
+static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
+{
+       producer_libdv this = producer->child;
+       uint8_t *data = malloc( frame_size_625_50 );
+       
+       // Obtain the current frame number
+       uint64_t position = mlt_producer_frame( producer );
+       
+       // Convert timecode to a file position (ensuring that we're on a frame boundary)
+       uint64_t offset = position * this->frame_size;
+
+       // Create an empty frame
+       *frame = mlt_frame_init( );
+
+       // Seek and fetch
+       if ( this->fd != 0 && 
+                lseek( this->fd, offset, SEEK_SET ) == offset &&
+                read_frame( this->fd, data, &this->is_pal ) )
+       {
+               // Get the frames properties
+               mlt_properties properties = mlt_frame_properties( *frame );
+
+               // Pass the dv decoder
+               mlt_properties_set_data( properties, "dv_decoder", this->dv_decoder, 0, NULL, NULL );
+
+               // Pass the dv data
+               mlt_properties_set_data( properties, "dv_data", data, frame_size_625_50, free, NULL );
+
+               // Update other info on the frame
+               mlt_properties_set_int( properties, "width", 720 );
+               mlt_properties_set_int( properties, "height", this->is_pal ? 576 : 480 );
+
+               // Hmm - register audio callback
+               ( *frame )->get_audio = producer_get_audio;
+               
+               // Push the get_image method on to the stack
+               mlt_frame_push_get_image( *frame, producer_get_image );
+       }
+       else
+       {
+               free( data );
+       }
+
+       // Update timecode on the frame we're creating
+       mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) );
+
+       // Calculate the next timecode
+       mlt_producer_prepare_next( producer );
+
+       return 0;
+}
+
+static void producer_close( mlt_producer parent )
+{
+       // Obtain this
+       producer_libdv this = parent->child;
+
+       // Free the dv deconder
+       dv_decoder_free( this->dv_decoder );
+
+       // Close the file
+       if ( this->fd != 0 )
+               close( this->fd );
+
+       // Close the parent
+       parent->close = NULL;
+       mlt_producer_close( parent );
+
+       // Free the memory
+       free( this );
+}
+
diff --git a/mlt/src/modules/dv/producer_libdv.h b/mlt/src/modules/dv/producer_libdv.h
new file mode 100644 (file)
index 0000000..c493eae
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * producer_libdv.h -- a DV decoder based on libdv
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _PRODUCER_LIBDV_H_
+#define _PRODUCER_LIBDV_H_
+
+#include <framework/mlt_producer.h>
+
+extern mlt_producer producer_libdv_init( char *filename );
+
+#endif
diff --git a/mlt/src/modules/gtk2/Makefile b/mlt/src/modules/gtk2/Makefile
new file mode 100644 (file)
index 0000000..0136b31
--- /dev/null
@@ -0,0 +1,29 @@
+
+TARGET = libmltgtk2.so
+
+OBJS = factory.o \
+          producer_pixbuf.o 
+
+CFLAGS=`pkg-config gdk-pixbuf-2.0 --cflags` -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread
+
+LDFLAGS=`pkg-config gdk-pixbuf-2.0 --libs`
+
+SRCS := $(OBJS:.o=.c)
+
+all:   $(TARGET)
+
+$(TARGET): $(OBJS)
+               $(CC) -shared -o $@ $(OBJS) $(LDFLAGS)
+
+depend:        $(SRCS)
+               $(CC) -MM $(CFLAGS) $^ 1>.depend
+
+dist-clean:    clean
+               rm -f .depend
+
+clean: 
+               rm -f $(OBJS) $(TARGET)
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/mlt/src/modules/gtk2/configure b/mlt/src/modules/gtk2/configure
new file mode 100755 (executable)
index 0000000..2112336
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+if [ "$help" != "1" ]
+then
+
+cat << EOF >> ../producers.dat
+pixbuf                 libmltgtk2.so
+EOF
+
+fi
+
diff --git a/mlt/src/modules/gtk2/factory.c b/mlt/src/modules/gtk2/factory.c
new file mode 100644 (file)
index 0000000..fc3a7fa
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * factory.c -- the factory method interfaces
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "producer_pixbuf.h"
+
+void *mlt_create_producer( char *id, void *arg )
+{
+       if ( !strcmp( id, "pixbuf" ) )
+               return producer_pixbuf_init( arg );
+       return NULL;
+}
+
+void *mlt_create_filter( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_transition( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_consumer( char *id, void *arg )
+{
+       return NULL;
+}
+
diff --git a/mlt/src/modules/gtk2/producer_pixbuf.c b/mlt/src/modules/gtk2/producer_pixbuf.c
new file mode 100644 (file)
index 0000000..8a74a46
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * producer_pixbuf.c -- raster image loader based upon gdk-pixbuf
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "producer_pixbuf.h"
+#include <framework/mlt_frame.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index );
+static void producer_close( mlt_producer parent );
+
+mlt_producer producer_pixbuf_init( const char *filename )
+{
+       producer_pixbuf this = calloc( sizeof( struct producer_pixbuf_s ), 1 );
+       if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 )
+       {
+               mlt_producer producer = &this->parent;
+
+               producer->get_frame = producer_get_frame;
+               producer->close = producer_close;
+
+               this->filename = strdup( filename );
+               this->counter = -1;
+               g_type_init();
+
+               return producer;
+       }
+       free( this );
+       return NULL;
+}
+
+static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
+{
+       // Obtain properties of frame
+       mlt_properties properties = mlt_frame_properties( this );
+
+       // May need to know the size of the image to clone it
+       int size = 0;
+
+       // Get the image
+       uint8_t *image = mlt_properties_get_data( properties, "image", &size );
+
+       // Get width and height
+       *width = mlt_properties_get_int( properties, "width" );
+       *height = mlt_properties_get_int( properties, "height" );
+
+       // Clone if necessary
+       if ( writable )
+       {
+               // Clone our image
+               uint8_t *copy = malloc( size );
+               memcpy( copy, image, size );
+
+               // We're going to pass the copy on
+               image = copy;
+
+               // Now update properties so we free the copy after
+               mlt_properties_set_data( properties, "image", copy, size, free, NULL );
+       }
+
+       // Pass on the image
+       *buffer = image;
+
+       return 0;
+}
+
+uint8_t *producer_get_alpha_mask( mlt_frame this )
+{
+       // Obtain properties of frame
+       mlt_properties properties = mlt_frame_properties( this );
+
+       // Return the alpha mask
+       return mlt_properties_get_data( properties, "alpha", NULL );
+}
+
+static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
+{
+       producer_pixbuf this = producer->child;
+       GdkPixbuf *pixbuf = NULL;
+       GError *error = NULL;
+
+       // Generate a frame
+       *frame = mlt_frame_init( );
+
+       // Obtain properties of frame
+       mlt_properties properties = mlt_frame_properties( *frame );
+
+    // optimization for subsequent iterations on single picture
+       if ( this->image != NULL )
+       {
+               // Set width/height
+               mlt_properties_set_int( properties, "width", this->width );
+               mlt_properties_set_int( properties, "height", this->height );
+
+               // if picture sequence pass the image and alpha data without destructor
+               mlt_properties_set_data( properties, "image", this->image, 0, NULL, NULL );
+               mlt_properties_set_data( properties, "alpha", this->alpha, 0, NULL, NULL );
+
+               // Set alpha mask call back
+        ( *frame )->get_alpha_mask = producer_get_alpha_mask;
+
+               // Stack the get image callback
+               mlt_frame_push_get_image( *frame, producer_get_image );
+
+       }
+       else if ( strchr( this->filename, '%' ) != NULL )
+       {
+               // handle picture sequences
+               char filename[1024];
+               filename[1023] = 0;
+               int current = this->counter;
+               do
+               {
+                       ++this->counter;
+                       snprintf( filename, 1023, this->filename, this->counter );
+                       pixbuf = gdk_pixbuf_new_from_file( filename, &error );
+                       // allow discontinuity in frame numbers up to 99
+                       error = NULL;
+               } while ( pixbuf == NULL && ( this->counter - current ) < 100 );
+       }
+       else
+       {
+               pixbuf = gdk_pixbuf_new_from_file( this->filename, &error );
+       }
+
+       // If we have a pixbuf
+       if ( pixbuf )
+       {
+               // Store width and height
+               this->width = gdk_pixbuf_get_width( pixbuf );
+               this->height = gdk_pixbuf_get_height( pixbuf );
+
+               // Allocate/define image and alpha
+               uint8_t *image = malloc( this->width * this->height * 2 );
+               uint8_t *alpha = NULL;
+
+               // Extract YUV422 and alpha
+               if ( gdk_pixbuf_get_has_alpha( pixbuf ) )
+               {
+                       // Allocate the alpha mask
+                       alpha = malloc( this->width * this->height );
+
+                       // Convert the image
+                       mlt_convert_rgb24a_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ),
+                                                                                 this->width, this->height,
+                                                                                 gdk_pixbuf_get_rowstride( pixbuf ),
+                                                                                 image, alpha );
+               }
+               else
+               { 
+                       // No alpha to extract
+                       mlt_convert_rgb24_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ),
+                                                                                this->width, this->height,
+                                                                                gdk_pixbuf_get_rowstride( pixbuf ),
+                                                                                image );
+               }
+
+               // Finished with pixbuf now
+               g_object_unref( pixbuf );
+
+               // Set width/height of frame
+               mlt_properties_set_int( properties, "width", this->width );
+               mlt_properties_set_int( properties, "height", this->height );
+
+               // Pass alpha and image on properties with or without destructor
+               if ( this->counter >= 0 )
+               {
+                       // if picture sequence pass the image and alpha data with destructor
+                       mlt_properties_set_data( properties, "image", image, 0, free, NULL );
+                       mlt_properties_set_data( properties, "alpha", alpha, 0, free, NULL );
+               }
+               else
+               {
+                       // if single picture, reference the image and alpha in the producer
+                       this->image = image;
+                       this->alpha = alpha;
+
+                       // pass the image and alpha data without destructor
+                       mlt_properties_set_data( properties, "image", image, 0, NULL, NULL );
+                       mlt_properties_set_data( properties, "alpha", alpha, 0, NULL, NULL );
+               }
+
+               // Set alpha call back
+               ( *frame )->get_alpha_mask = producer_get_alpha_mask;
+
+               // Push the get_image method
+               mlt_frame_push_get_image( *frame, producer_get_image );
+       }
+
+       // Update timecode on the frame we're creating
+       mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) );
+
+       // Calculate the next timecode
+       mlt_producer_prepare_next( producer );
+
+       return 0;
+}
+
+static void producer_close( mlt_producer parent )
+{
+       producer_pixbuf this = parent->child;
+       if ( this->filename )
+               free( this->filename );
+       if ( this->image )
+               free( this->image );
+       if ( this->alpha )
+               free( this->alpha );
+       parent->close = NULL;
+       mlt_producer_close( parent );
+       free( this );
+}
+
diff --git a/mlt/src/modules/gtk2/producer_pixbuf.h b/mlt/src/modules/gtk2/producer_pixbuf.h
new file mode 100644 (file)
index 0000000..c7f76ef
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * producer_pixbuf.h -- raster image loader based upon gdk-pixbuf
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _PRODUCER_PIXBUF_H_
+#define _PRODUCER_PIXBUF_H_
+
+#include <framework/mlt_producer.h>
+
+typedef struct producer_pixbuf_s *producer_pixbuf;
+
+struct producer_pixbuf_s
+{
+       struct mlt_producer_s parent;
+       char *filename;
+       int counter;
+       int width;
+       int height;
+       uint8_t *image;
+       uint8_t *alpha;
+};
+
+extern mlt_producer producer_pixbuf_init( const char *filename );
+
+#endif
diff --git a/mlt/src/modules/sdl/Makefile b/mlt/src/modules/sdl/Makefile
new file mode 100644 (file)
index 0000000..5107441
--- /dev/null
@@ -0,0 +1,29 @@
+
+TARGET = libmltsdl.so
+
+OBJS = factory.o \
+          consumer_sdl.o 
+
+CFLAGS=-I../../ `sdl-config --cflags` -Wall -g -D_FILE_OFFSET_BITS=64 -pthread
+
+LDFLAGS= `sdl-config --libs`
+
+SRCS := $(OBJS:.o=.c)
+
+all:   $(TARGET)
+
+$(TARGET): $(OBJS)
+               $(CC) -shared -o $@ $(OBJS) $(LDFLAGS)
+
+depend:        $(SRCS)
+               $(CC) -MM $(CFLAGS) $^ 1>.depend
+
+dist-clean:    clean
+               rm -f .depend
+
+clean: 
+               rm -f $(OBJS) $(TARGET)
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/mlt/src/modules/sdl/configure b/mlt/src/modules/sdl/configure
new file mode 100755 (executable)
index 0000000..1c40fac
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+if [ "$help" != "1" ]
+then
+
+cat << EOF >> ../consumers.dat
+sdl                            libmltsdl.so
+EOF
+
+fi
+
diff --git a/mlt/src/modules/sdl/consumer_sdl.c b/mlt/src/modules/sdl/consumer_sdl.c
new file mode 100644 (file)
index 0000000..59196d2
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * consumer_sdl.c -- A Simple DirectMedia Layer consumer
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "consumer_sdl.h"
+#include <framework/mlt_frame.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <SDL/SDL.h>
+#include <SDL/SDL_syswm.h>
+
+/** This classes definition.
+*/
+
+typedef struct consumer_sdl_s *consumer_sdl;
+
+struct consumer_sdl_s
+{
+       struct mlt_consumer_s parent;
+       mlt_properties properties;
+       int format;
+       int video;
+       pthread_t thread;
+       int running;
+       uint8_t audio_buffer[ 4096 * 6 ];
+       int audio_avail;
+       pthread_mutex_t audio_mutex;
+       pthread_cond_t audio_cond;
+       int window_width;
+       int window_height;
+};
+
+/** Forward references to static functions.
+*/
+
+static void consumer_close( mlt_consumer parent );
+static void *consumer_thread( void * );
+static void consumer_get_dimensions( int *width, int *height );
+
+/** This is what will be called by the factory - anything can be passed in
+       via the argument, but keep it simple.
+*/
+
+mlt_consumer consumer_sdl_init( void *dummy )
+{
+       // Create the consumer object
+       consumer_sdl this = calloc( sizeof( struct consumer_sdl_s ), 1 );
+
+       // If no malloc'd and consumer init ok
+       if ( this != NULL && mlt_consumer_init( &this->parent, this ) == 0 )
+       {
+               // Get the parent consumer object
+               mlt_consumer parent = &this->parent;
+
+               // We have stuff to clean up, so override the close method
+               parent->close = consumer_close;
+
+               // get a handle on properties
+               mlt_service service = mlt_consumer_service( parent );
+               this->properties = mlt_service_properties( service );
+
+               // Set the default volume
+               mlt_properties_set_double( this->properties, "volume", 1.0 );
+
+               // This is the initialisation of the consumer
+               this->running = 1;
+               pthread_mutex_init( &this->audio_mutex, NULL );
+               pthread_cond_init( &this->audio_cond, NULL);
+               
+               // TODO: process actual param
+               
+               // Create the the thread
+               pthread_create( &this->thread, NULL, consumer_thread, this );
+
+               // Return the consumer produced
+               return parent;
+       }
+
+       // malloc or consumer init failed
+       free( this );
+
+       // Indicate failure
+       return NULL;
+}
+
+static int sdl_lock_display( )
+{
+       SDL_Surface *screen = SDL_GetVideoSurface( );
+       return screen != NULL && ( !SDL_MUSTLOCK( screen ) || SDL_LockSurface( screen ) >= 0 );
+}
+
+static void sdl_unlock_display( )
+{
+       SDL_Surface *screen = SDL_GetVideoSurface( );
+       if ( screen != NULL && SDL_MUSTLOCK( screen ) )
+               SDL_UnlockSurface( screen );
+}
+
+void sdl_fill_audio( void *udata, Uint8 *stream, int len )
+{
+       consumer_sdl this = udata;
+
+       // Get the volume
+       float volume = mlt_properties_get_double( this->properties, "volume" );
+
+       pthread_mutex_lock( &this->audio_mutex );
+
+       // Experimental - block until audio received
+       while ( this->running && len > this->audio_avail )
+               pthread_cond_wait( &this->audio_cond, &this->audio_mutex );
+
+       if ( this->audio_avail >= len )
+       {
+               // Place in the audio buffer
+               SDL_MixAudio( stream, this->audio_buffer, len, ( int )( ( float )SDL_MIX_MAXVOLUME * volume ) );
+
+               // Remove len from the audio available
+               this->audio_avail -= len;
+
+               // Remove the samples
+               memmove( this->audio_buffer, this->audio_buffer + len, this->audio_avail );
+       }
+       else
+       {
+               // Just to be safe, wipe the stream first
+               memset( stream, 0, len );
+
+               // Copy what we have into the stream
+               memcpy( stream, this->audio_buffer, this->audio_avail );
+
+               // Mix the audio 
+               SDL_MixAudio( stream, stream, len, ( int )( ( float )SDL_MIX_MAXVOLUME * volume ) );
+
+               // No audio left
+               this->audio_avail = 0;
+       }
+       pthread_cond_broadcast( &this->audio_cond );
+       pthread_mutex_unlock( &this->audio_mutex );
+}
+
+/** Threaded wrapper for pipe.
+*/
+
+static void *consumer_thread( void *arg )
+{
+       // Identify the arg
+       consumer_sdl this = arg;
+
+       // Get the consumer
+       mlt_consumer consumer = &this->parent;
+
+       // Get the service assoicated to the consumer
+       mlt_service service = mlt_consumer_service( consumer );
+
+       // Define a frame pointer
+       mlt_frame frame;
+
+       // internal intialization
+       int sdl_flags = SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_HWACCEL | SDL_RESIZABLE;
+       SDL_Surface *sdl_screen = NULL;
+       SDL_Overlay *sdl_overlay = NULL;
+       uint8_t *buffer = NULL;
+       int init_audio = 1;
+       int bytes;
+
+       if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ) < 0 )
+       {
+               fprintf( stderr, "Failed to initialize SDL: %s\n", SDL_GetError() );
+               return NULL;
+       }
+       
+       // Loop until told not to
+       while( this->running )
+       {
+               // Get a frame from the service (should never return anything other than 0)
+               if ( mlt_service_get_frame( service, &frame, 0 ) == 0 )
+               {
+                       mlt_image_format vfmt = mlt_image_yuv422;
+                       int width, height;
+                       uint8_t *image;
+
+                       mlt_audio_format afmt = mlt_audio_pcm;
+                       int channels;
+                       int samples;
+                       int frequency;
+                       int16_t *pcm;
+
+                       mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples );
+                       if ( init_audio == 1 )
+                       {
+                               SDL_AudioSpec request;
+
+                               // specify audio format
+                               request.freq = frequency;
+                               request.format = AUDIO_S16;
+                               request.channels = channels;
+                               request.samples = 1024;
+                               request.callback = sdl_fill_audio;
+                               request.userdata = (void *)this;
+                               if ( SDL_OpenAudio( &request, NULL ) < 0 )
+                               {
+                                       fprintf( stderr, "SDL failed to open audio: %s\n", SDL_GetError() );
+                                       break;
+                               }
+                               SDL_PauseAudio( 0 );
+                               init_audio = 0;
+                       }
+                       bytes = ( samples * channels * 2 );
+                       pthread_mutex_lock( &this->audio_mutex );
+                       while ( bytes > ( sizeof( this->audio_buffer) - this->audio_avail ) )
+                               pthread_cond_wait( &this->audio_cond, &this->audio_mutex );
+                       memcpy( &this->audio_buffer[ this->audio_avail ], pcm, bytes );
+                       this->audio_avail += bytes;
+                       pthread_cond_broadcast( &this->audio_cond );
+                       pthread_mutex_unlock( &this->audio_mutex );
+
+                       // Get the image, width and height
+                       mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 );
+                       if ( width != this->window_width || height != this->window_height )
+                       {
+                               SDL_Rect rect;
+                               this->window_width = rect.w = width;
+                               this->window_height = rect.h = height;
+
+                               // open SDL window with video overlay, if possible
+                               if ( sdl_screen == NULL )
+                                       sdl_screen = SDL_SetVideoMode( width, height, 0, sdl_flags );
+                               if ( sdl_screen != NULL )
+                               {
+                                       rect.x = rect.y = 0;
+
+
+                                       // XXX: this is a little hack until we have some sort of aspect
+                                       // ratio property on images.
+                                       if ( rect.h <= 486 )
+                                       {
+                                               rect.w = 640;
+                                               rect.x = ( 720 - 640 ) / 2;
+                                       }
+                                       else
+                                       {
+                                               rect.h = 540;
+                                               rect.y = ( 576 - 540 ) / 2;
+                                       }
+
+                                       SDL_SetClipRect( sdl_screen, &rect );
+                                       
+                                       // Force an overlay recreation
+                                       if ( sdl_overlay != NULL )
+                                               SDL_FreeYUVOverlay( sdl_overlay );
+                                       sdl_lock_display();
+                                       sdl_overlay = SDL_CreateYUVOverlay( width, height, SDL_YUY2_OVERLAY, sdl_screen );
+                                       sdl_unlock_display();
+                               }
+                       }
+                       
+                       if ( sdl_screen != NULL && sdl_overlay != NULL )
+                       {
+                               buffer = sdl_overlay->pixels[ 0 ];
+                               if ( sdl_lock_display() )
+                               {
+                                       if ( SDL_LockYUVOverlay( sdl_overlay ) >= 0 )
+                                       {
+                                               memcpy( buffer, image, width * height * 2 );
+                                               SDL_UnlockYUVOverlay( sdl_overlay );
+                                               SDL_DisplayYUVOverlay( sdl_overlay, &sdl_screen->clip_rect );
+                                       }
+                                       sdl_unlock_display();
+                               }
+                       }
+                       else
+                       {
+                               // TODO: allocate buffer?
+                       }
+
+                       // Close the frame
+                       mlt_frame_close( frame );
+               }
+               else
+               {
+                       break;
+               }
+       } // while
+
+       // internal cleanup
+       if ( init_audio == 0 )
+               SDL_AudioQuit( );
+       if ( sdl_overlay != NULL )
+               SDL_FreeYUVOverlay( sdl_overlay );
+       SDL_Quit( );
+
+       return NULL;
+}
+
+static void consumer_get_dimensions( int *width, int *height )
+{
+       // SDL windows manager structure
+       SDL_SysWMinfo wm;
+
+       // Specify the SDL Version
+       SDL_VERSION( &wm.version );
+
+       // Get the wm structure
+       if ( SDL_GetWMInfo( &wm ) == 1 )
+       {
+               // Check that we have the X11 wm
+               if ( wm.subsystem == SDL_SYSWM_X11 ) 
+               {
+                       // Get the SDL window
+                       Window window = wm.info.x11.window;
+
+                       // Get the display session
+                       Display *display = wm.info.x11.display;
+
+                       // Get the window attributes
+                       XWindowAttributes attr;
+                       XGetWindowAttributes( display, window, &attr );
+
+                       // Return width and height
+                       *width = attr.width;
+                       *height = attr.height;
+               }
+       }
+}
+
+/** Callback to allow override of the close method.
+*/
+
+static void consumer_close( mlt_consumer parent )
+{
+       // Get the actual object
+       consumer_sdl this = parent->child;
+
+       // Kill the thread and clean up
+       this->running = 0;
+       pthread_join( this->thread, NULL );
+
+       pthread_mutex_destroy( &this->audio_mutex );
+       pthread_cond_destroy( &this->audio_cond );
+               
+       // Now clean up the rest (the close = NULL is a bit nasty but needed for now)
+       parent->close = NULL;
+       mlt_consumer_close( parent );
+
+       // Finally clean up this
+       free( this );
+}
+
diff --git a/mlt/src/modules/sdl/consumer_sdl.h b/mlt/src/modules/sdl/consumer_sdl.h
new file mode 100644 (file)
index 0000000..6c8114e
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * consumer_sdl.h -- A Simple DirectMedia Layer consumer
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CONSUMER_SDL_H_
+#define _CONSUMER_SDL_H_
+
+#include <framework/mlt_consumer.h>
+
+extern mlt_consumer consumer_sdl_init( void * );
+
+#endif
diff --git a/mlt/src/modules/sdl/factory.c b/mlt/src/modules/sdl/factory.c
new file mode 100644 (file)
index 0000000..9e5f56e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * factory.c -- the factory method interfaces
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "consumer_sdl.h"
+
+void *mlt_create_producer( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_filter( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_transition( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_consumer( char *id, void *arg )
+{
+       if ( !strcmp( id, "sdl" ) )
+               return consumer_sdl_init( arg );
+       return NULL;
+}
+
diff --git a/mlt/src/tests/charlie.c b/mlt/src/tests/charlie.c
new file mode 100644 (file)
index 0000000..174cb20
--- /dev/null
@@ -0,0 +1,79 @@
+#include "mlt_producer.h"
+#include "mlt_consumer.h"
+#include "mlt_filter.h"
+#include "mlt_tractor.h"
+#include "mlt_transition.h"
+#include "mlt_multitrack.h"
+
+#include "producer_libdv.h"
+#include "producer_ppm.h"
+#include "filter_deinterlace.h"
+#include "filter_greyscale.h"
+#include "consumer_sdl.h"
+
+#include <stdio.h>
+
+int main( int argc, char **argv )
+{
+       char temp[ 132 ];
+       char *file1 = NULL;
+       char *file2 = NULL;
+
+       // Start the consumer...
+       mlt_consumer sdl_out = consumer_sdl_init( NULL );
+
+       fprintf( stderr, "Press return to continue\n" );
+       fgets( temp, 132, stdin );
+
+       if ( argc >= 2 )
+               file1 = argv[ 1 ];
+       if ( argc >= 3 )
+               file2 = argv[ 2 ];
+
+       // Create the producer(s)
+       //mlt_producer dv1 = producer_ppm_init( NULL );
+       //mlt_producer dv2 = producer_ppm_init( NULL );
+       mlt_producer dv1 = producer_libdv_init( file1 );
+       mlt_producer dv2 = producer_libdv_init( file2 );
+
+       mlt_consumer_connect( sdl_out, mlt_producer_service( dv1 ) );
+
+       fprintf( stderr, "Press return to continue\n" );
+       fgets( temp, 132, stdin );
+
+       // Register producers(s) with a multitrack object
+       mlt_multitrack multitrack = mlt_multitrack_init( );
+       mlt_multitrack_connect( multitrack, dv1, 0 );
+       mlt_multitrack_connect( multitrack, dv2, 1 );
+
+       // Create a filter and associate it to track 0
+       mlt_filter filter = filter_deinterlace_init( NULL );
+       mlt_filter_connect( filter, mlt_multitrack_service( multitrack ), 0 );
+       mlt_filter_set_in_and_out( filter, 0, 5 );
+
+       // Create another
+       mlt_filter greyscale = filter_greyscale_init( NULL );
+       mlt_filter_connect( greyscale, mlt_filter_service( filter ), 0 );
+       mlt_filter_set_in_and_out( greyscale, 0, 10 );
+
+       // Buy a tractor and connect it to the filter
+       mlt_tractor tractor = mlt_tractor_init( );
+       mlt_tractor_connect( tractor, mlt_filter_service( greyscale ) );
+
+       // Connect the tractor to the consumer
+       mlt_consumer_connect( sdl_out, mlt_tractor_service( tractor ) );
+
+       // Do stuff until we're told otherwise...
+       fprintf( stderr, "Press return to continue\n" );
+       fgets( temp, 132, stdin );
+
+       // Close everything...
+       mlt_consumer_close( sdl_out );
+       mlt_tractor_close( tractor );
+       mlt_filter_close( filter );
+       mlt_multitrack_close( multitrack );
+       mlt_producer_close( dv1 );
+       mlt_producer_close( dv2 );
+
+       return 0;
+}
diff --git a/mlt/src/tests/dan.c b/mlt/src/tests/dan.c
new file mode 100644 (file)
index 0000000..ee76bb0
--- /dev/null
@@ -0,0 +1,72 @@
+#include "mlt_producer.h"
+#include "mlt_consumer.h"
+#include "mlt_filter.h"
+#include "mlt_tractor.h"
+#include "mlt_transition.h"
+#include "mlt_multitrack.h"
+
+#include "producer_libdv.h"
+#include "filter_deinterlace.h"
+#include "consumer_sdl.h"
+#include "producer_ppm.h"
+#include "producer_pixbuf.h"
+#include "transition_composite.h"
+
+#include <stdio.h>
+
+int main( int argc, char **argv )
+{
+       char temp[ 132 ];
+       char *file1 = NULL;
+       char *file2 = NULL;
+
+       if ( argc >= 2 )
+               file1 = argv[ 1 ];
+       if ( argc >= 3 )
+               file2 = argv[ 2 ];
+
+       // Start the consumer...
+       mlt_consumer sdl_out = consumer_sdl_init( NULL );
+
+       // Create the producer(s)
+       mlt_producer dv1 = producer_libdv_init( file1 );
+       //mlt_producer dv1 = producer_pixbuf_init( file1 );
+       //mlt_producer dv2 = producer_libdv_init( file2 );
+       mlt_producer dv2 = producer_pixbuf_init( file2 );
+
+       // Register producers(s) with a multitrack object
+       mlt_multitrack multitrack = mlt_multitrack_init( );
+       mlt_multitrack_connect( multitrack, dv1, 0 );
+       mlt_multitrack_connect( multitrack, dv2, 1 );
+
+       // Create a filter and associate it to track 0
+       mlt_filter filter = filter_deinterlace_init( NULL );
+       mlt_filter_connect( filter, mlt_multitrack_service( multitrack ), 0 );
+       mlt_filter_set_in_and_out( filter, 0, 1000 );
+
+       // Define a transition
+       mlt_transition transition = transition_composite_init( NULL );
+       mlt_transition_connect( transition, mlt_filter_service( filter ), 0, 1 );
+       mlt_transition_set_in_and_out( transition, 0, 1000 );
+
+       // Buy a tractor and connect it to the filter
+       mlt_tractor tractor = mlt_tractor_init( );
+       mlt_tractor_connect( tractor, mlt_transition_service( transition ) );
+
+       // Connect the tractor to the consumer
+       mlt_consumer_connect( sdl_out, mlt_tractor_service( tractor ) );
+
+       // Do stuff until we're told otherwise...
+       fprintf( stderr, "Press return to continue\n" );
+       fgets( temp, 132, stdin );
+
+       // Close everything...
+       mlt_consumer_close( sdl_out );
+       mlt_tractor_close( tractor );
+       mlt_filter_close( filter );
+       mlt_multitrack_close( multitrack );
+       mlt_producer_close( dv1 );
+       mlt_producer_close( dv2 );
+
+       return 0;
+}
diff --git a/mlt/src/tests/test.png b/mlt/src/tests/test.png
new file mode 100644 (file)
index 0000000..b3fca64
Binary files /dev/null and b/mlt/src/tests/test.png differ
diff --git a/mlt/src/valerie/Makefile b/mlt/src/valerie/Makefile
new file mode 100644 (file)
index 0000000..908c432
--- /dev/null
@@ -0,0 +1,37 @@
+
+AR = ar
+
+OBJS = valerie.o \
+          valerie_notifier.o \
+          valerie_parser.o \
+          valerie_response.o \
+          valerie_status.o \
+          valerie_tokeniser.o \
+          valerie_util.o \
+          valerie_remote.o \
+          valerie_socket.o
+
+SRCS := $(OBJS:.o=.c)
+
+CFLAGS=-Wall -g -D_FILE_OFFSET_BITS=64 -pthread
+
+LDFLAGS=-ldv -lpthread
+
+all: libvalerie.a
+
+libvalerie.a: $(OBJS)
+       $(AR) rvu $@ $(OBJS)
+       ranlib $@
+
+depend:        $(SRCS)
+               $(CC) -MM $(CFLAGS) $^ 1>.depend
+
+dist-clean:    clean
+               rm -f .depend
+
+clean: 
+               rm -f $(OBJS) libvalerie.a 
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/mlt/src/valerie/configure b/mlt/src/valerie/configure
new file mode 100755 (executable)
index 0000000..1a24852
--- /dev/null
@@ -0,0 +1 @@
+#!/bin/sh
diff --git a/mlt/src/valerie/valerie.c b/mlt/src/valerie/valerie.c
new file mode 100644 (file)
index 0000000..2e1f289
--- /dev/null
@@ -0,0 +1,875 @@
+/*
+ * valerie.c -- High Level Client API for miracle
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+/* Application header files */
+#include "valerie.h"
+#include "valerie_tokeniser.h"
+#include "valerie_util.h"
+
+/** Initialise the valerie structure.
+*/
+
+valerie valerie_init( valerie_parser parser )
+{
+       valerie this = malloc( sizeof( valerie_t ) );
+       if ( this != NULL )
+       {
+               memset( this, 0, sizeof( valerie_t ) );
+               this->parser = parser;
+       }
+       return this;
+}
+
+/** Set the response structure associated to the last command.
+*/
+
+static void valerie_set_last_response( valerie this, valerie_response response )
+{
+       if ( this != NULL )
+       {
+               if ( this->last_response != NULL )
+                       valerie_response_close( this->last_response );
+               this->last_response = response;
+       }
+}
+
+/** Connect to the parser.
+*/
+
+valerie_error_code valerie_connect( valerie this )
+{
+       valerie_error_code error = valerie_server_unavailable;
+       valerie_response response = valerie_parser_connect( this->parser );
+       if ( response != NULL )
+       {
+               valerie_set_last_response( this, response );
+               if ( valerie_response_get_error_code( response ) == 100 )
+                       error = valerie_ok;
+       }
+       return error;
+}
+
+/** Interpret a non-context sensitive error code.
+*/
+
+static valerie_error_code valerie_get_error_code( valerie this, valerie_response response )
+{
+       valerie_error_code error = valerie_server_unavailable;
+       switch( valerie_response_get_error_code( response ) )
+       {
+               case -1:
+                       error = valerie_server_unavailable;
+                       break;
+               case -2:
+                       error = valerie_no_response;
+                       break;
+               case 200:
+               case 201:
+               case 202:
+                       error = valerie_ok;
+                       break;
+               case 400:
+                       error = valerie_invalid_command;
+                       break;
+               case 401:
+                       error = valerie_server_timeout;
+                       break;
+               case 402:
+                       error = valerie_missing_argument;
+                       break;
+               case 403:
+                       error = valerie_unit_unavailable;
+                       break;
+               case 404:
+                       error = valerie_invalid_file;
+                       break;
+               default:
+               case 500:
+                       error = valerie_unknown_error;
+                       break;
+       }
+       return error;
+}
+
+/** Execute a command.
+*/
+
+valerie_error_code valerie_execute( valerie this, size_t size, char *format, ... )
+{
+       valerie_error_code error = valerie_server_unavailable;
+       char *command = malloc( size );
+       if ( this != NULL && command != NULL )
+       {
+               va_list list;
+               va_start( list, format );
+               if ( vsnprintf( command, size, format, list ) != 0 )
+               {
+                       valerie_response response = valerie_parser_execute( this->parser, command );
+                       valerie_set_last_response( this, response );
+                       error = valerie_get_error_code( this, response );
+               }
+               else
+               {
+                       error = valerie_invalid_command;
+               }
+               va_end( list );
+       }
+       else
+       {
+               error = valerie_malloc_failed;
+       }
+       free( command );
+       return error;
+}
+
+/** Set a global property.
+*/
+
+valerie_error_code valerie_set( valerie this, char *property, char *value )
+{
+       return valerie_execute( this, 1024, "SET %s=%s", property, value );
+}
+
+/** Get a global property.
+*/
+
+valerie_error_code valerie_get( valerie this, char *property, char *value, int length )
+{
+       valerie_error_code error = valerie_execute( this, 1024, "GET %s", property );
+       if ( error == valerie_ok )
+       {
+               valerie_response response = valerie_get_last_response( this );
+               strncpy( value, valerie_response_get_line( response, 1 ), length );
+       }
+       return error;
+}
+
+/** Run a script.
+*/
+
+valerie_error_code valerie_run( valerie this, char *file )
+{
+       return valerie_execute( this, 10240, "RUN \"%s\"", file );
+}
+
+/** Add a unit.
+*/
+
+valerie_error_code valerie_unit_add( valerie this, char *guid, int *unit )
+{
+       valerie_error_code error = valerie_execute( this, 1024, "UADD %s", guid );
+       if ( error == valerie_ok )
+       {
+               int length = valerie_response_count( this->last_response );
+               char *line = valerie_response_get_line( this->last_response, length - 2 );
+               if ( line == NULL || sscanf( line, "U%d", unit ) != 1 )
+                       error = valerie_unit_creation_failed;
+       }
+       else
+       {
+               if ( error == valerie_unknown_error )
+                       error = valerie_unit_creation_failed;
+       }
+       return error;
+}
+
+/** Load a file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_load( valerie this, int unit, char *file )
+{
+       return valerie_execute( this, 10240, "LOAD U%d \"%s\"", unit, file );
+}
+
+static void valerie_interpret_clip_offset( char *output, valerie_clip_offset offset, int clip )
+{
+       switch( offset )
+       {
+               case valerie_absolute:
+                       sprintf( output, "%d", clip );
+                       break;
+               case valerie_relative:
+                       if ( clip < 0 )
+                               sprintf( output, "%d", clip );
+                       else
+                               sprintf( output, "+%d", clip );
+                       break;
+       }
+}
+
+/** Load a file on the specified unit with the specified in/out points.
+*/
+
+valerie_error_code valerie_unit_load_clipped( valerie this, int unit, char *file, double in, double out )
+{
+       return valerie_execute( this, 10240, "LOAD U%d \"%s\" %e %e", unit, file, in, out );
+}
+
+/** Load a file on the specified unit at the end of the current pump.
+*/
+
+valerie_error_code valerie_unit_load_back( valerie this, int unit, char *file )
+{
+       return valerie_execute( this, 10240, "LOAD U%d \"!%s\"", unit, file );
+}
+
+/** Load a file on the specified unit at the end of the pump with the specified in/out points.
+*/
+
+valerie_error_code valerie_unit_load_back_clipped( valerie this, int unit, char *file, double in, double out )
+{
+       return valerie_execute( this, 10240, "LOAD U%d \"!%s\" %e %e", unit, file, in, out );
+}
+
+/** Append a file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_append( valerie this, int unit, char *file, double in, double out )
+{
+       return valerie_execute( this, 10240, "APND U%d \"%s\" %e %e", unit, file, in, out );
+}
+
+/** Clean the unit - this function removes all but the currently playing clip.
+*/
+
+valerie_error_code valerie_unit_clean( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "CLEAN U%d", unit );
+}
+
+/** Move clips on the units playlist.
+*/
+
+valerie_error_code valerie_unit_clip_move( valerie this, int unit, valerie_clip_offset src_offset, int src, valerie_clip_offset dest_offset, int dest )
+{
+       char temp1[ 100 ];
+       char temp2[ 100 ];
+       valerie_interpret_clip_offset( temp1, src_offset, src );
+       valerie_interpret_clip_offset( temp2, dest_offset, dest );
+       return valerie_execute( this, 1024, "MOVE U%d %s %s", unit, temp1, temp2 );
+}
+
+/** Remove clip at the specified position.
+*/
+
+valerie_error_code valerie_unit_clip_remove( valerie this, int unit, valerie_clip_offset offset, int clip )
+{
+       char temp[ 100 ];
+       valerie_interpret_clip_offset( temp, offset, clip );
+       return valerie_execute( this, 1024, "REMOVE U%d %s", unit, temp );
+}
+
+/** Remove the currently playing clip.
+*/
+
+valerie_error_code valerie_unit_remove_current_clip( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "REMOVE U%d", unit );
+}
+
+/** Insert clip at the specified position.
+*/
+
+valerie_error_code valerie_unit_clip_insert( valerie this, int unit, valerie_clip_offset offset, int clip, char *file, double in, double out )
+{
+       char temp[ 100 ];
+       valerie_interpret_clip_offset( temp, offset, clip );
+       return valerie_execute( this, 1024, "INSERT U%d %s %s %e %e", unit, file, temp, in, out );
+}
+
+/** Play the unit at normal speed.
+*/
+
+valerie_error_code valerie_unit_play( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "PLAY U%d 1000", unit );
+}
+
+/** Play the unit at specified speed.
+*/
+
+valerie_error_code valerie_unit_play_at_speed( valerie this, int unit, double speed )
+{
+       return valerie_execute( this, 10240, "PLAY U%d %e", unit, speed );
+}
+
+/** Stop playback on the specified unit.
+*/
+
+valerie_error_code valerie_unit_stop( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "STOP U%d", unit );
+}
+
+/** Pause playback on the specified unit.
+*/
+
+valerie_error_code valerie_unit_pause( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "PAUSE U%d", unit );
+}
+
+/** Rewind the specified unit.
+*/
+
+valerie_error_code valerie_unit_rewind( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "REW U%d", unit );
+}
+
+/** Fast forward the specified unit.
+*/
+
+valerie_error_code valerie_unit_fast_forward( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "FF U%d", unit );
+}
+
+/** Step by the number of frames on the specified unit.
+*/
+
+valerie_error_code valerie_unit_step( valerie this, int unit, double step )
+{
+       return valerie_execute( this, 1024, "STEP U%d %e", unit, step );
+}
+
+/** Goto the specified frame on the specified unit.
+*/
+
+valerie_error_code valerie_unit_goto( valerie this, int unit, double position )
+{
+       return valerie_execute( this, 1024, "GOTO U%d %e", unit, position );
+}
+
+/** Goto the specified frame in the clip on the specified unit.
+*/
+
+valerie_error_code valerie_unit_clip_goto( valerie this, int unit, valerie_clip_offset offset, int clip, double position )
+{
+       char temp[ 100 ];
+       valerie_interpret_clip_offset( temp, offset, clip );
+       return valerie_execute( this, 1024, "GOTO U%d %e %s", unit, position, temp );
+}
+
+/** Set the in point of the loaded file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_set_in( valerie this, int unit, double in )
+{
+       return valerie_execute( this, 1024, "SIN U%d %e", unit, in );
+}
+
+/** Set the in point of the clip on the specified unit.
+*/
+
+valerie_error_code valerie_unit_clip_set_in( valerie this, int unit, valerie_clip_offset offset, int clip, double in )
+{
+       char temp[ 100 ];
+       valerie_interpret_clip_offset( temp, offset, clip );
+       return valerie_execute( this, 1024, "SIN U%d %e %s", unit, in, temp );
+}
+
+/** Set the out point of the loaded file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_set_out( valerie this, int unit, double out )
+{
+       return valerie_execute( this, 1024, "SOUT U%d %e", unit, out );
+}
+
+/** Set the out point of the clip on the specified unit.
+*/
+
+valerie_error_code valerie_unit_clip_set_out( valerie this, int unit, valerie_clip_offset offset, int clip, double in )
+{
+       char temp[ 100 ];
+       valerie_interpret_clip_offset( temp, offset, clip );
+       return valerie_execute( this, 1024, "SOUT U%d %e %s", unit, in, temp );
+}
+
+/** Clear the in point of the loaded file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_clear_in( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "SIN U%d -1", unit );
+}
+
+/** Clear the out point of the loaded file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_clear_out( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "SOUT U%d -1", unit );
+}
+
+/** Clear the in and out points on the loaded file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_clear_in_out( valerie this, int unit )
+{
+       valerie_error_code error = valerie_unit_clear_out( this, unit );
+       if ( error == valerie_ok )
+               error = valerie_unit_clear_in( this, unit );
+       return error;
+}
+
+/** Set a unit configuration property.
+*/
+
+valerie_error_code valerie_unit_set( valerie this, int unit, char *name, char *value )
+{
+       return valerie_execute( this, 1024, "USET U%d %s=%s", unit, name, value );
+}
+
+/** Get a unit configuration property.
+*/
+
+valerie_error_code valerie_unit_get( valerie this, int unit, char *name )
+{
+       return valerie_execute( this, 1024, "UGET U%d %s", unit, name );
+}
+
+/** Get a units status.
+*/
+
+valerie_error_code valerie_unit_status( valerie this, int unit, valerie_status status )
+{
+       valerie_error_code error = valerie_execute( this, 1024, "USTA U%d", unit );
+       int error_code = valerie_response_get_error_code( this->last_response );
+
+       memset( status, 0, sizeof( valerie_status_t ) );
+       status->unit = unit;
+       if ( error_code == 202 && valerie_response_count( this->last_response ) == 2 )
+               valerie_status_parse( status, valerie_response_get_line( this->last_response, 1 ) );
+       else if ( error_code == 403 )
+               status->status = unit_undefined;
+
+       return error;
+}
+
+/** Transfer the current settings of unit src to unit dest.
+*/
+
+valerie_error_code valerie_unit_transfer( valerie this, int src, int dest )
+{
+       return valerie_execute( this, 1024, "XFER U%d U%d", src, dest );
+}
+
+/** Obtain the parsers notifier.
+*/
+
+valerie_notifier valerie_get_notifier( valerie this )
+{
+       if ( this != NULL )
+               return valerie_parser_get_notifier( this->parser );
+       else
+               return NULL;
+}
+
+/** List the contents of the specified directory.
+*/
+
+valerie_dir valerie_dir_init( valerie this, char *directory )
+{
+       valerie_dir dir = malloc( sizeof( valerie_dir_t ) );
+       if ( dir != NULL )
+       {
+               memset( dir, 0, sizeof( valerie_dir_t ) );
+               dir->directory = strdup( directory );
+               dir->response = valerie_parser_executef( this->parser, "CLS \"%s\"", directory );
+       }
+       return dir;
+}
+
+/** Return the error code associated to the dir.
+*/
+
+valerie_error_code valerie_dir_get_error_code( valerie_dir dir )
+{
+       if ( dir != NULL )
+               return valerie_get_error_code( NULL, dir->response );
+       else
+               return valerie_malloc_failed;
+}
+
+/** Get a particular file entry in the directory.
+*/
+
+valerie_error_code valerie_dir_get( valerie_dir dir, int index, valerie_dir_entry entry )
+{
+       valerie_error_code error = valerie_ok;
+       memset( entry, 0, sizeof( valerie_dir_entry_t ) );
+       if ( index < valerie_dir_count( dir ) )
+       {
+               char *line = valerie_response_get_line( dir->response, index + 1 );
+               valerie_tokeniser tokeniser = valerie_tokeniser_init( );
+               valerie_tokeniser_parse_new( tokeniser, line, " " );
+
+               if ( valerie_tokeniser_count( tokeniser ) > 0 )
+               {
+                       valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 0 ), '\"' );
+                       strcpy( entry->full, dir->directory );
+                       if ( entry->full[ strlen( entry->full ) - 1 ] != '/' )
+                               strcat( entry->full, "/" );
+                       strcpy( entry->name, valerie_tokeniser_get_string( tokeniser, 0 ) );
+                       strcat( entry->full, entry->name );
+
+                       switch ( valerie_tokeniser_count( tokeniser ) )
+                       {
+                               case 1:
+                                       entry->dir = 1;
+                                       break;
+                               case 2:
+                                       entry->size = strtoull( valerie_tokeniser_get_string( tokeniser, 1 ), NULL, 10 );
+                                       break;
+                               default:
+                                       error = valerie_invalid_file;
+                                       break;
+                       }
+               }
+               valerie_tokeniser_close( tokeniser );
+       }
+       return error;
+}
+
+/** Get the number of entries in the directory
+*/
+
+int valerie_dir_count( valerie_dir dir )
+{
+       if ( dir != NULL && valerie_response_count( dir->response ) >= 2 )
+               return valerie_response_count( dir->response ) - 2;
+       else
+               return -1;
+}
+
+/** Close the directory structure.
+*/
+
+void valerie_dir_close( valerie_dir dir )
+{
+       if ( dir != NULL )
+       {
+               free( dir->directory );
+               valerie_response_close( dir->response );
+               free( dir );
+       }
+}
+
+/** List the playlist of the specified unit.
+*/
+
+valerie_list valerie_list_init( valerie this, int unit )
+{
+       valerie_list list = calloc( 1, sizeof( valerie_list_t ) );
+       if ( list != NULL )
+       {
+               list->response = valerie_parser_executef( this->parser, "LIST U%d", unit );
+               if ( valerie_response_count( list->response ) >= 2 )
+                       list->generation = atoi( valerie_response_get_line( list->response, 1 ) );
+       }
+       return list;
+}
+
+/** Return the error code associated to the list.
+*/
+
+valerie_error_code valerie_list_get_error_code( valerie_list list )
+{
+       if ( list != NULL )
+               return valerie_get_error_code( NULL, list->response );
+       else
+               return valerie_malloc_failed;
+}
+
+/** Get a particular file entry in the list.
+*/
+
+valerie_error_code valerie_list_get( valerie_list list, int index, valerie_list_entry entry )
+{
+       valerie_error_code error = valerie_ok;
+       memset( entry, 0, sizeof( valerie_list_entry_t ) );
+       if ( index < valerie_list_count( list ) )
+       {
+               char *line = valerie_response_get_line( list->response, index + 2 );
+               valerie_tokeniser tokeniser = valerie_tokeniser_init( );
+               valerie_tokeniser_parse_new( tokeniser, line, " " );
+
+               if ( valerie_tokeniser_count( tokeniser ) > 0 )
+               {
+                       entry->clip = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) );
+                       valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 1 ), '\"' );
+                       strcpy( entry->full, valerie_tokeniser_get_string( tokeniser, 1 ) );
+                       entry->in = atof( valerie_tokeniser_get_string( tokeniser, 2 ) );
+                       entry->out = atof( valerie_tokeniser_get_string( tokeniser, 3 ) );
+                       entry->max = atof( valerie_tokeniser_get_string( tokeniser, 4 ) );
+                       entry->size = atof( valerie_tokeniser_get_string( tokeniser, 5 ) );
+                       entry->fps = atof( valerie_tokeniser_get_string( tokeniser, 6 ) );
+               }
+               valerie_tokeniser_close( tokeniser );
+       }
+       return error;
+}
+
+/** Get the number of entries in the list
+*/
+
+int valerie_list_count( valerie_list list )
+{
+       if ( list != NULL && valerie_response_count( list->response ) >= 3 )
+               return valerie_response_count( list->response ) - 3;
+       else
+               return -1;
+}
+
+/** Close the list structure.
+*/
+
+void valerie_list_close( valerie_list list )
+{
+       if ( list != NULL )
+       {
+               valerie_response_close( list->response );
+               free( list );
+       }
+}
+
+/** List the currently connected nodes.
+*/
+
+valerie_nodes valerie_nodes_init( valerie this )
+{
+       valerie_nodes nodes = malloc( sizeof( valerie_nodes_t ) );
+       if ( nodes != NULL )
+       {
+               memset( nodes, 0, sizeof( valerie_nodes_t ) );
+               nodes->response = valerie_parser_executef( this->parser, "NLS" );
+       }
+       return nodes;
+}
+
+/** Return the error code associated to the nodes list.
+*/
+
+valerie_error_code valerie_nodes_get_error_code( valerie_nodes nodes )
+{
+       if ( nodes != NULL )
+               return valerie_get_error_code( NULL, nodes->response );
+       else
+               return valerie_malloc_failed;
+}
+
+/** Get a particular node entry.
+*/
+
+valerie_error_code valerie_nodes_get( valerie_nodes nodes, int index, valerie_node_entry entry )
+{
+       valerie_error_code error = valerie_ok;
+       memset( entry, 0, sizeof( valerie_node_entry_t ) );
+       if ( index < valerie_nodes_count( nodes ) )
+       {
+               char *line = valerie_response_get_line( nodes->response, index + 1 );
+               valerie_tokeniser tokeniser = valerie_tokeniser_init( );
+               valerie_tokeniser_parse_new( tokeniser, line, " " );
+
+               if ( valerie_tokeniser_count( tokeniser ) == 3 )
+               {
+                       entry->node = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) );
+                       strncpy( entry->guid, valerie_tokeniser_get_string( tokeniser, 1 ), sizeof( entry->guid ) );
+                       valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 2 ), '\"' );
+                       strncpy( entry->name, valerie_tokeniser_get_string( tokeniser, 2 ), sizeof( entry->name ) );
+               }
+
+               valerie_tokeniser_close( tokeniser );
+       }
+       return error;
+}
+
+/** Get the number of nodes
+*/
+
+int valerie_nodes_count( valerie_nodes nodes )
+{
+       if ( nodes != NULL && valerie_response_count( nodes->response ) >= 2 )
+               return valerie_response_count( nodes->response ) - 2;
+       else
+               return -1;
+}
+
+/** Close the nodes structure.
+*/
+
+void valerie_nodes_close( valerie_nodes nodes )
+{
+       if ( nodes != NULL )
+       {
+               valerie_response_close( nodes->response );
+               free( nodes );
+       }
+}
+
+/** List the currently defined units.
+*/
+
+valerie_units valerie_units_init( valerie this )
+{
+       valerie_units units = malloc( sizeof( valerie_units_t ) );
+       if ( units != NULL )
+       {
+               memset( units, 0, sizeof( valerie_units_t ) );
+               units->response = valerie_parser_executef( this->parser, "ULS" );
+       }
+       return units;
+}
+
+/** Return the error code associated to the nodes list.
+*/
+
+valerie_error_code valerie_units_get_error_code( valerie_units units )
+{
+       if ( units != NULL )
+               return valerie_get_error_code( NULL, units->response );
+       else
+               return valerie_malloc_failed;
+}
+
+/** Get a particular unit entry.
+*/
+
+valerie_error_code valerie_units_get( valerie_units units, int index, valerie_unit_entry entry )
+{
+       valerie_error_code error = valerie_ok;
+       memset( entry, 0, sizeof( valerie_unit_entry_t ) );
+       if ( index < valerie_units_count( units ) )
+       {
+               char *line = valerie_response_get_line( units->response, index + 1 );
+               valerie_tokeniser tokeniser = valerie_tokeniser_init( );
+               valerie_tokeniser_parse_new( tokeniser, line, " " );
+
+               if ( valerie_tokeniser_count( tokeniser ) == 4 )
+               {
+                       entry->unit = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) + 1 );
+                       entry->node = atoi( valerie_tokeniser_get_string( tokeniser, 1 ) );
+                       strncpy( entry->guid, valerie_tokeniser_get_string( tokeniser, 2 ), sizeof( entry->guid ) );
+                       entry->online = atoi( valerie_tokeniser_get_string( tokeniser, 3 ) );
+               }
+
+               valerie_tokeniser_close( tokeniser );
+       }
+       return error;
+}
+
+/** Get the number of units
+*/
+
+int valerie_units_count( valerie_units units )
+{
+       if ( units != NULL && valerie_response_count( units->response ) >= 2 )
+               return valerie_response_count( units->response ) - 2;
+       else
+               return -1;
+}
+
+/** Close the units structure.
+*/
+
+void valerie_units_close( valerie_units units )
+{
+       if ( units != NULL )
+       {
+               valerie_response_close( units->response );
+               free( units );
+       }
+}
+
+/** Get the response of the last command executed.
+*/
+
+valerie_response valerie_get_last_response( valerie this )
+{
+       return this->last_response;
+}
+
+/** Obtain a printable message associated to the error code provided.
+*/
+
+char *valerie_error_description( valerie_error_code error )
+{
+       char *msg = "Unrecognised error";
+       switch( error )
+       {
+               case valerie_ok:
+                       msg = "OK";
+                       break;
+               case valerie_malloc_failed:
+                       msg = "Memory allocation error";
+                       break;
+               case valerie_unknown_error:
+                       msg = "Unknown error";
+                       break;
+               case valerie_no_response:
+                       msg = "No response obtained";
+                       break;
+               case valerie_invalid_command:
+                       msg = "Invalid command";
+                       break;
+               case valerie_server_timeout:
+                       msg = "Communications with server timed out";
+                       break;
+               case valerie_missing_argument:
+                       msg = "Missing argument";
+                       break;
+               case valerie_server_unavailable:
+                       msg = "Unable to communicate with server";
+                       break;
+               case valerie_unit_creation_failed:
+                       msg = "Unit creation failed";
+                       break;
+               case valerie_unit_unavailable:
+                       msg = "Unit unavailable";
+                       break;
+               case valerie_invalid_file:
+                       msg = "Invalid file";
+                       break;
+               case valerie_invalid_position:
+                       msg = "Invalid position";
+                       break;
+       }
+       return msg;
+}
+
+/** Close the valerie structure.
+*/
+
+void valerie_close( valerie this )
+{
+       if ( this != NULL )
+       {
+               valerie_set_last_response( this, NULL );
+               free( this );
+       }
+}
diff --git a/mlt/src/valerie/valerie.h b/mlt/src/valerie/valerie.h
new file mode 100644 (file)
index 0000000..91c0987
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * valerie.h -- High Level Client API for miracle
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _VALERIE_H_
+#define _VALERIE_H_
+
+/* System header files */
+#include <limits.h>
+
+/* Application header files */
+#include "valerie_parser.h"
+#include "valerie_status.h"
+#include "valerie_notifier.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Client error conditions
+*/
+
+typedef enum
+{
+       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
+}
+valerie_error_code;
+
+/** Clip index specification.
+*/
+
+typedef enum
+{
+       valerie_absolute = 0,
+       valerie_relative
+}
+valerie_clip_offset;
+
+/** Client structure.
+*/
+
+typedef struct
+{
+       valerie_parser parser;
+       valerie_response last_response;
+}
+*valerie, valerie_t;
+
+/** Client API.
+*/
+
+extern valerie valerie_init( valerie_parser );
+
+/* Connect to the valerie parser instance */
+extern valerie_error_code valerie_connect( valerie );
+
+/* Global functions */
+extern valerie_error_code valerie_set( valerie, char *, char * );
+extern valerie_error_code valerie_get( valerie, char *, char *, int );
+extern valerie_error_code valerie_run( valerie, char * );
+
+/* Unit functions */
+extern valerie_error_code valerie_unit_add( valerie, char *, int * );
+extern valerie_error_code valerie_unit_load( valerie, int, char * );
+extern valerie_error_code valerie_unit_load_clipped( valerie, int, char *, double, double );
+extern valerie_error_code valerie_unit_load_back( valerie, int, char * );
+extern valerie_error_code valerie_unit_load_back_clipped( valerie, int, char *, double, double );
+extern valerie_error_code valerie_unit_append( valerie, int, char *, double, double );
+extern valerie_error_code valerie_unit_clean( valerie, int );
+extern valerie_error_code valerie_unit_clip_move( valerie, int, valerie_clip_offset, int, valerie_clip_offset, int );
+extern valerie_error_code valerie_unit_clip_remove( valerie, int, valerie_clip_offset, int );
+extern valerie_error_code valerie_unit_remove_current_clip( valerie, int );
+extern valerie_error_code valerie_unit_clip_insert( valerie, int, valerie_clip_offset, int, char *, double, double );
+extern valerie_error_code valerie_unit_play( valerie, int );
+extern valerie_error_code valerie_unit_play_at_speed( valerie, int, double );
+extern valerie_error_code valerie_unit_stop( valerie, int );
+extern valerie_error_code valerie_unit_pause( valerie, int );
+extern valerie_error_code valerie_unit_rewind( valerie, int );
+extern valerie_error_code valerie_unit_fast_forward( valerie, int );
+extern valerie_error_code valerie_unit_step( valerie, int, double );
+extern valerie_error_code valerie_unit_goto( valerie, int, double );
+extern valerie_error_code valerie_unit_clip_goto( valerie, int, valerie_clip_offset, int, double );
+extern valerie_error_code valerie_unit_clip_set_in( valerie, int, valerie_clip_offset, int, double );
+extern valerie_error_code valerie_unit_clip_set_out( valerie, int, valerie_clip_offset, int, double );
+extern valerie_error_code valerie_unit_set_in( valerie, int, double );
+extern valerie_error_code valerie_unit_set_out( valerie, int, double );
+extern valerie_error_code valerie_unit_clear_in( valerie, int );
+extern valerie_error_code valerie_unit_clear_out( valerie, int );
+extern valerie_error_code valerie_unit_clear_in_out( valerie, int );
+extern valerie_error_code valerie_unit_set( valerie, int, char *, char * );
+extern valerie_error_code valerie_unit_get( valerie, int, char * );
+extern valerie_error_code valerie_unit_status( valerie, int, valerie_status );
+extern valerie_error_code valerie_unit_transfer( valerie, int, int );
+
+/* Notifier functionality. */
+extern valerie_notifier valerie_get_notifier( valerie );
+
+/** Structure for the directory.
+*/
+
+typedef struct
+{
+       char *directory;
+       valerie_response response;
+}
+*valerie_dir, valerie_dir_t;
+
+/** Directory entry structure.
+*/
+
+typedef struct
+{
+       int dir;
+       char name[ NAME_MAX ];
+       char full[ PATH_MAX + NAME_MAX ];
+       unsigned long long size;
+}
+*valerie_dir_entry, valerie_dir_entry_t;
+
+/* Directory reading. */
+extern valerie_dir valerie_dir_init( valerie, char * );
+extern valerie_error_code valerie_dir_get_error_code( valerie_dir );
+extern valerie_error_code valerie_dir_get( valerie_dir, int, valerie_dir_entry );
+extern int valerie_dir_count( valerie_dir );
+extern void valerie_dir_close( valerie_dir );
+
+/** Structure for the list.
+*/
+
+typedef struct
+{
+       int generation;
+       valerie_response response;
+}
+*valerie_list, valerie_list_t;
+
+/** List entry structure.
+*/
+
+typedef struct
+{
+       int clip;
+       char full[ PATH_MAX + NAME_MAX ];
+       double in;
+       double out;
+       double max;
+       double size;
+       double fps;
+}
+*valerie_list_entry, valerie_list_entry_t;
+
+/* List reading. */
+extern valerie_list valerie_list_init( valerie, int );
+extern valerie_error_code valerie_list_get_error_code( valerie_list );
+extern valerie_error_code valerie_list_get( valerie_list, int, valerie_list_entry );
+extern int valerie_list_count( valerie_list );
+extern void valerie_list_close( valerie_list );
+
+/** Structure for nodes.
+*/
+
+typedef struct
+{
+       valerie_response response;
+}
+*valerie_nodes, valerie_nodes_t;
+
+/** Node entry structure.
+*/
+
+typedef struct
+{
+       int node;
+       char guid[ 17 ];
+       char name[ 1024 ];
+}
+*valerie_node_entry, valerie_node_entry_t;
+
+/* Node reading. */
+extern valerie_nodes valerie_nodes_init( valerie );
+extern valerie_error_code valerie_nodes_get_error_code( valerie_nodes );
+extern valerie_error_code valerie_nodes_get( valerie_nodes, int, valerie_node_entry );
+extern int valerie_nodes_count( valerie_nodes );
+extern void valerie_nodes_close( valerie_nodes );
+
+/** Structure for units.
+*/
+
+typedef struct
+{
+       valerie_response response;
+}
+*valerie_units, valerie_units_t;
+
+/** Unit entry structure.
+*/
+
+typedef struct
+{
+       int unit;
+       int node;
+       char guid[ 17 ];
+       int online;
+}
+*valerie_unit_entry, valerie_unit_entry_t;
+
+/* Unit reading. */
+extern valerie_units valerie_units_init( valerie );
+extern valerie_error_code valerie_units_get_error_code( valerie_units );
+extern valerie_error_code valerie_units_get( valerie_units, int, valerie_unit_entry );
+extern int valerie_units_count( valerie_units );
+extern void valerie_units_close( valerie_units );
+
+/* Miscellaenous functions */
+extern valerie_response valerie_get_last_response( valerie );
+extern char *valerie_error_description( valerie_error_code );
+
+/* Courtesy functions. */
+extern valerie_error_code valerie_execute( valerie, size_t, char *, ... );
+
+/* Close function. */
+extern void valerie_close( valerie );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/valerie/valerie_notifier.c b/mlt/src/valerie/valerie_notifier.c
new file mode 100644 (file)
index 0000000..5e374a8
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * valerie_notifier.c -- Unit Status Notifier Handling
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+
+/* Application header files */
+#include "valerie_notifier.h"
+
+/** Notifier initialisation.
+*/
+
+valerie_notifier valerie_notifier_init( )
+{
+       valerie_notifier this = malloc( sizeof( valerie_notifier_t ) );
+       if ( this != NULL )
+       {
+               int index = 0;
+               memset( this, 0, sizeof( valerie_notifier_t ) );
+               pthread_mutex_init( &this->mutex, NULL );
+               pthread_cond_init( &this->cond, NULL );
+               pthread_mutex_init( &this->cond_mutex, NULL );
+               for ( index = 0; index < MAX_UNITS; index ++ )
+                       this->store[ index ].unit = index;
+       }
+       return this;
+}
+
+/** Get a stored status for the specified unit.
+*/
+
+void valerie_notifier_get( valerie_notifier this, valerie_status status, int unit )
+{
+       pthread_mutex_lock( &this->mutex );
+       if ( unit >= 0 && unit < MAX_UNITS )
+       {
+               valerie_status_copy( status, &this->store[ unit ] );
+       }
+       else
+       {
+               memset( status, 0, sizeof( valerie_status_t ) );
+               status->unit = unit;
+       }
+       status->dummy = time( NULL );
+       pthread_mutex_unlock( &this->mutex );
+}
+
+/** Wait on a new status.
+*/
+
+int valerie_notifier_wait( valerie_notifier this, valerie_status status )
+{
+       struct timeval now;
+       struct timespec timeout;
+       int error = 0;
+
+       memset( status, 0, sizeof( valerie_status_t ) );
+
+       pthread_mutex_lock( &this->cond_mutex );
+       gettimeofday( &now, NULL );
+       timeout.tv_sec = now.tv_sec + 1;
+       timeout.tv_nsec = now.tv_usec * 1000;
+       if ( pthread_cond_timedwait( &this->cond, &this->cond_mutex, &timeout ) != ETIMEDOUT )
+       {
+               pthread_mutex_lock( &this->mutex );
+               valerie_status_copy( status, &this->last );
+               pthread_mutex_unlock( &this->mutex );
+       }
+       else
+       {
+               error = -1;
+       }
+       pthread_mutex_unlock( &this->cond_mutex );
+
+       return error;
+}
+
+/** Put a new status.
+*/
+
+void valerie_notifier_put( valerie_notifier this, valerie_status status )
+{
+       pthread_mutex_lock( &this->mutex );
+       valerie_status_copy( &this->store[ status->unit ], status );
+       valerie_status_copy( &this->last, status );
+       pthread_mutex_unlock( &this->mutex );
+       pthread_cond_broadcast( &this->cond );
+}
+
+/** Communicate a disconnected status for all units to all waiting.
+*/
+
+void valerie_notifier_disconnected( valerie_notifier notifier )
+{
+       int unit = 0;
+       valerie_status_t status;
+       for ( unit = 0; unit < MAX_UNITS; unit ++ )
+       {
+               valerie_notifier_get( notifier, &status, unit );
+               status.status = unit_disconnected;
+               valerie_notifier_put( notifier, &status );
+       }
+}
+
+/** Close the notifier - note that all access must be stopped before we call this.
+*/
+
+void valerie_notifier_close( valerie_notifier this )
+{
+       if ( this != NULL )
+       {
+               pthread_mutex_destroy( &this->mutex );
+               pthread_mutex_destroy( &this->cond_mutex );
+               pthread_cond_destroy( &this->cond );
+               free( this );
+       }
+}
diff --git a/mlt/src/valerie/valerie_notifier.h b/mlt/src/valerie/valerie_notifier.h
new file mode 100644 (file)
index 0000000..bc123ed
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * valerie_notifier.h -- Unit Status Notifier Handling
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_NOTIFIER_H_
+#define _VALERIE_NOTIFIER_H_
+
+/* System header files */
+#include <pthread.h>
+
+/* Application header files */
+#include "valerie_status.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define MAX_UNITS 16
+
+/** Status notifier definition.
+*/
+
+typedef struct
+{
+       pthread_mutex_t mutex;
+       pthread_mutex_t cond_mutex;
+       pthread_cond_t cond;
+       valerie_status_t last;
+       valerie_status_t store[ MAX_UNITS ];
+}
+*valerie_notifier, valerie_notifier_t;
+
+extern valerie_notifier valerie_notifier_init( );
+extern void valerie_notifier_get( valerie_notifier, valerie_status, int );
+extern int valerie_notifier_wait( valerie_notifier, valerie_status );
+extern void valerie_notifier_put( valerie_notifier, valerie_status );
+extern void valerie_notifier_disconnected( valerie_notifier );
+extern void valerie_notifier_close( valerie_notifier );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/valerie/valerie_parser.c b/mlt/src/valerie/valerie_parser.c
new file mode 100644 (file)
index 0000000..4ead1c0
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * valerie_parser.c -- Valerie Parser for Miracle
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Application header files */
+#include "valerie_parser.h"
+#include "valerie_util.h"
+
+/** Connect to the parser.
+*/
+
+valerie_response valerie_parser_connect( valerie_parser parser )
+{
+       return parser->connect( parser->real );
+}
+
+/** Execute a command via the parser.
+*/
+
+valerie_response valerie_parser_execute( valerie_parser parser, char *command )
+{
+       return parser->execute( parser->real, command );
+}
+
+/** Execute a formatted command via the parser.
+*/
+
+valerie_response valerie_parser_executef( valerie_parser parser, char *format, ... )
+{
+       char *command = malloc( 10240 );
+       valerie_response response = NULL;
+       if ( command != NULL )
+       {
+               va_list list;
+               va_start( list, format );
+               if ( vsnprintf( command, 10240, format, list ) != 0 )
+                       response = valerie_parser_execute( parser, command );
+               va_end( list );
+               free( command );
+       }
+       return response;
+}
+
+/** Execute the contents of a file. Note the special case valerie_response returned.
+*/
+
+valerie_response valerie_parser_run( valerie_parser parser, char *filename )
+{
+       valerie_response response = valerie_response_init( );
+       if ( response != NULL )
+       {
+               FILE *file = fopen( filename, "r" );
+               if ( file != NULL )
+               {
+                       char command[ 1024 ];
+                       valerie_response_set_error( response, 201, "OK" );
+                       while ( valerie_response_get_error_code( response ) == 201 && fgets( command, 1024, file ) )
+                       {
+                               valerie_util_trim( valerie_util_chomp( command ) );
+                               if ( strcmp( command, "" ) && command[ 0 ] != '#' )
+                               {
+                                       valerie_response temp = NULL;
+                                       valerie_response_printf( response, 1024, "%s\n", command );
+                                       temp = valerie_parser_execute( parser, command );
+                                       if ( temp != NULL )
+                                       {
+                                               int index = 0;
+                                               for ( index = 0; index < valerie_response_count( temp ); index ++ )
+                                                       valerie_response_printf( response, 10240, "%s\n", valerie_response_get_line( temp, index ) );
+                                               valerie_response_close( temp );
+                                       }
+                                       else
+                                       {
+                                               valerie_response_set_error( response, 500, "Batch execution failed" );
+                                       }
+                               }
+                       }
+                       fclose( file );
+               }
+               else
+               {
+                       valerie_response_set_error( response, 404, "File not found." );
+               }
+       }
+       return response;
+}
+
+/** Get the notifier associated to the parser.
+*/
+
+valerie_notifier valerie_parser_get_notifier( valerie_parser parser )
+{
+       if ( parser->notifier == NULL )
+               parser->notifier = valerie_notifier_init( );
+       return parser->notifier;
+}
+
+/** Close the parser.
+*/
+
+void valerie_parser_close( valerie_parser parser )
+{
+       if ( parser != NULL )
+       {
+               parser->close( parser->real );
+               valerie_notifier_close( parser->notifier );
+               free( parser );
+       }
+}
diff --git a/mlt/src/valerie/valerie_parser.h b/mlt/src/valerie/valerie_parser.h
new file mode 100644 (file)
index 0000000..71446d9
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * valerie_parser.h -- Valerie Parser for Miracle Server
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_PARSER_H_
+#define _VALERIE_PARSER_H_
+
+/* Application header files */
+#include "valerie_response.h"
+#include "valerie_notifier.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Callbacks to define the parser.
+*/
+
+typedef valerie_response (*parser_connect)( void * );
+typedef valerie_response (*parser_execute)( void *, char * );
+typedef void (*parser_close)( void * );
+
+/** Structure for the valerie parser.
+*/
+
+typedef struct
+{
+       parser_connect connect;
+       parser_execute execute;
+       parser_close close;
+       void *real;
+       valerie_notifier notifier;
+}
+*valerie_parser, valerie_parser_t;
+
+/** API for the parser - note that no constructor is defined here.
+*/
+
+extern valerie_response valerie_parser_connect( valerie_parser );
+extern valerie_response valerie_parser_execute( valerie_parser, char * );
+extern valerie_response valerie_parser_executef( valerie_parser, char *, ... );
+extern valerie_response valerie_parser_run( valerie_parser, char * );
+extern valerie_notifier valerie_parser_get_notifier( valerie_parser );
+extern void valerie_parser_close( valerie_parser );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/valerie/valerie_remote.c b/mlt/src/valerie/valerie_remote.c
new file mode 100644 (file)
index 0000000..4b5023e
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * valerie_remote.c -- Remote Parser
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <pthread.h>
+
+/* Application header files */
+#include "valerie_remote.h"
+#include "valerie_socket.h"
+#include "valerie_tokeniser.h"
+#include "valerie_util.h"
+
+/** Private valerie_remote structure.
+*/
+
+typedef struct
+{
+       int terminated;
+       char *server;
+       int port;
+       valerie_socket socket;
+       valerie_socket status;
+       pthread_t thread;
+       valerie_parser parser;
+       pthread_mutex_t mutex;
+       int connected;
+}
+*valerie_remote, valerie_remote_t;
+
+/** Forward declarations.
+*/
+
+static valerie_response valerie_remote_connect( valerie_remote );
+static valerie_response valerie_remote_execute( valerie_remote, char * );
+static void valerie_remote_close( valerie_remote );
+static int valerie_remote_read_response( valerie_socket, valerie_response );
+
+/** DV Parser constructor.
+*/
+
+valerie_parser valerie_parser_init_remote( char *server, int port )
+{
+       valerie_parser parser = malloc( sizeof( valerie_parser_t ) );
+       valerie_remote remote = malloc( sizeof( valerie_remote_t ) );
+
+       if ( parser != NULL )
+       {
+               memset( parser, 0, sizeof( valerie_parser_t ) );
+
+               parser->connect = (parser_connect)valerie_remote_connect;
+               parser->execute = (parser_execute)valerie_remote_execute;
+               parser->close = (parser_close)valerie_remote_close;
+               parser->real = remote;
+
+               if ( remote != NULL )
+               {
+                       memset( remote, 0, sizeof( valerie_remote_t ) );
+                       remote->parser = parser;
+                       remote->server = strdup( server );
+                       remote->port = port;
+                       pthread_mutex_init( &remote->mutex, NULL );
+               }
+       }
+       return parser;
+}
+
+/** Thread for receiving and distributing the status information.
+*/
+
+static void *valerie_remote_status_thread( void *arg )
+{
+       valerie_remote remote = arg;
+       char temp[ 10240 ];
+       int length = 0;
+       int offset = 0;
+       valerie_tokeniser tokeniser = valerie_tokeniser_init( );
+       valerie_notifier notifier = valerie_parser_get_notifier( remote->parser );
+       valerie_status_t status;
+       int index = 0;
+
+       valerie_socket_write_data( remote->status, "STATUS\r\n", 8 );
+
+       while ( !remote->terminated && 
+                       ( length = valerie_socket_read_data( remote->status, temp + offset, sizeof( temp ) ) ) >= 0 )
+       {
+               if ( strchr( temp, '\n' ) == NULL )
+               {
+                       offset = length;
+                       continue;
+               }
+               offset = 0;
+               valerie_tokeniser_parse_new( tokeniser, temp, "\n" );
+               for ( index = 0; index < valerie_tokeniser_count( tokeniser ); index ++ )
+               {
+                       char *line = valerie_tokeniser_get_string( tokeniser, index );
+                       if ( line[ strlen( line ) - 1 ] == '\r' )
+                       {
+                               valerie_util_chomp( line );
+                               valerie_status_parse( &status, line );
+                               valerie_notifier_put( notifier, &status );
+                       }
+                       else
+                       {
+                               strcpy( temp, line );
+                               offset = strlen( temp );
+                       }
+               }
+       }
+
+       valerie_notifier_disconnected( notifier );
+       valerie_tokeniser_close( tokeniser );
+       remote->terminated = 1;
+
+       return NULL;
+}
+
+/** Forward reference.
+*/
+
+static void valerie_remote_disconnect( valerie_remote remote );
+
+/** Connect to the server.
+*/
+
+static valerie_response valerie_remote_connect( valerie_remote remote )
+{
+       valerie_response response = NULL;
+
+       valerie_remote_disconnect( remote );
+
+       if ( !remote->connected )
+       {
+               signal( SIGPIPE, SIG_IGN );
+
+               remote->socket = valerie_socket_init( remote->server, remote->port );
+               remote->status = valerie_socket_init( remote->server, remote->port );
+
+               if ( valerie_socket_connect( remote->socket ) == 0 )
+               {
+                       response = valerie_response_init( );
+                       valerie_remote_read_response( remote->socket, response );
+               }
+
+               if ( response != NULL && valerie_socket_connect( remote->status ) == 0 )
+               {
+                       valerie_response status_response = valerie_response_init( );
+                       valerie_remote_read_response( remote->status, status_response );
+                       if ( valerie_response_get_error_code( status_response ) == 100 )
+                               pthread_create( &remote->thread, NULL, valerie_remote_status_thread, remote );
+                       valerie_response_close( status_response );
+                       remote->connected = 1;
+               }
+       }
+
+       return response;
+}
+
+/** Execute the command.
+*/
+
+static valerie_response valerie_remote_execute( valerie_remote remote, char *command )
+{
+       valerie_response response = NULL;
+       pthread_mutex_lock( &remote->mutex );
+       if ( valerie_socket_write_data( remote->socket, command, strlen( command ) ) == strlen( command ) )
+       {
+               response = valerie_response_init( );
+               valerie_socket_write_data( remote->socket, "\r\n", 2 );
+               valerie_remote_read_response( remote->socket, response );
+       }
+       pthread_mutex_unlock( &remote->mutex );
+       return response;
+}
+
+/** Disconnect.
+*/
+
+static void valerie_remote_disconnect( valerie_remote remote )
+{
+       if ( remote != NULL && remote->terminated )
+       {
+               pthread_join( remote->thread, NULL );
+               valerie_socket_close( remote->status );
+               valerie_socket_close( remote->socket );
+               remote->connected = 0;
+               remote->terminated = 0;
+       }
+}
+
+/** Close the parser.
+*/
+
+static void valerie_remote_close( valerie_remote remote )
+{
+       if ( remote != NULL )
+       {
+               remote->terminated = 1;
+               valerie_remote_disconnect( remote );
+               pthread_mutex_destroy( &remote->mutex );
+               free( remote->server );
+               free( remote );
+       }
+}
+
+/** Read response. 
+*/
+
+static int valerie_remote_read_response( valerie_socket socket, valerie_response response )
+{
+       char temp[ 10240 ];
+       int length;
+       int terminated = 0;
+
+       while ( !terminated && ( length = valerie_socket_read_data( socket, temp, 10240 ) ) >= 0 )
+       {
+               int position = 0;
+               temp[ length ] = '\0';
+               valerie_response_write( response, temp, length );
+               position = valerie_response_count( response ) - 1;
+               if ( position < 0 || temp[ strlen( temp ) - 1 ] != '\n' )
+                       continue;
+               switch( valerie_response_get_error_code( response ) )
+               {
+                       case 201:
+                       case 500:
+                               terminated = !strcmp( valerie_response_get_line( response, position ), "" );
+                               break;
+                       case 202:
+                               terminated = valerie_response_count( response ) >= 2;
+                               break;
+                       default:
+                               terminated = 1;
+                               break;
+               }
+       }
+
+       return 0;
+}
diff --git a/mlt/src/valerie/valerie_remote.h b/mlt/src/valerie/valerie_remote.h
new file mode 100644 (file)
index 0000000..291184a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * valerie_remote.h -- Remote Parser
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_REMOTE_H_
+#define _VALERIE_REMOTE_H_
+
+/* Application header files */
+#include "valerie_parser.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Remote parser API.
+*/
+
+extern valerie_parser valerie_parser_init_remote( char *, int );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/valerie/valerie_response.c b/mlt/src/valerie/valerie_response.c
new file mode 100644 (file)
index 0000000..5b9491c
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * valerie_response.c -- Response
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+/* Application header files */
+#include "valerie_response.h"
+
+/** Construct a new dv response.
+*/
+
+valerie_response valerie_response_init( )
+{
+       valerie_response response = malloc( sizeof( valerie_response_t ) );
+       if ( response != NULL )
+               memset( response, 0, sizeof( valerie_response_t ) );
+       return response;
+}
+
+/** Clone a dv response
+*/
+
+valerie_response valerie_response_clone( valerie_response response )
+{
+       valerie_response clone = valerie_response_init( );
+       if ( clone != NULL && response != NULL )
+       {
+               int index = 0;
+               for ( index = 0; index < valerie_response_count( response ); index ++ )
+               {
+                       char *line = valerie_response_get_line( response, index );
+                       valerie_response_printf( clone, strlen( line ) + 2, "%s\n", line );
+               }
+       }
+       return clone;
+}
+
+/** Get the error code associated to the response.
+*/
+
+int valerie_response_get_error_code( valerie_response response )
+{
+       int error_code = -1;
+       if ( response != NULL )
+       {
+               if ( response->count > 0 )
+               {
+                       if ( sscanf( response->array[ 0 ], "%d", &error_code ) != 1 )
+                               error_code = 0;
+               }
+               else
+               {
+                       error_code = -2;
+               }
+       }
+       return error_code;
+}
+
+/** Get the error description associated to the response.
+*/
+
+char *valerie_response_get_error_string( valerie_response response )
+{
+       char *error_string = "No message specified";
+       if ( response->count > 0 )
+       {
+               char *ptr = strchr( response->array[ 0 ], ' ' ) ;
+               if ( ptr != NULL )
+                       error_string = ptr + 1;
+       }
+       return error_string;
+}
+
+/** Get a line of text at the given index. Note that the text itself is
+       terminated only with a NUL char and it is the responsibility of the
+       the user of the returned data to use a LF or CR/LF as appropriate.
+*/
+
+char *valerie_response_get_line( valerie_response response, int index )
+{
+       if ( index < response->count )
+               return response->array[ index ];
+       else
+               return NULL;
+}
+
+/** Return the number of lines of text in the response.
+*/
+
+int valerie_response_count( valerie_response response )
+{
+       if ( response != NULL )
+               return response->count;
+       else
+               return 0;
+}
+
+/** Set the error and description associated to the response.
+*/
+
+void valerie_response_set_error( valerie_response response, int error_code, char *error_string )
+{
+       if ( response->count == 0 )
+       {
+               valerie_response_printf( response, 10240, "%d %s\n", error_code, error_string );
+       }
+       else
+       {
+               char temp[ 10240 ];
+               int length = sprintf( temp, "%d %s", error_code, error_string );
+               response->array[ 0 ] = realloc( response->array[ 0 ], length + 1 );
+               strcpy( response->array[ 0 ], temp );
+       }
+}
+
+/** Write formatted text to the response. 
+*/
+
+int valerie_response_printf( valerie_response response, size_t size, char *format, ... )
+{
+       int length = 0;
+       char *text = malloc( size );
+       if ( text != NULL )
+       {
+               va_list list;
+               va_start( list, format );
+               length = vsnprintf( text, size, format, list );
+               if ( length != 0 )
+                       valerie_response_write( response, text, length );
+               va_end( list );
+               free( text );
+       }
+       return length;
+}
+
+/** Write text to the reponse.
+*/
+
+int valerie_response_write( valerie_response response, char *text, int size )
+{
+       int ret = 0;
+       char *ptr = text;
+
+       while ( size > 0 )
+       {
+               int index = response->count - 1;
+               char *lf = strchr( ptr, '\n' );
+               int length_of_string = 0;
+
+               /* Make sure we have space in the dynamic array. */
+               if ( !response->append && response->count >= response->size - 1 )
+               {
+                       response->size += 50;
+                       response->array = realloc( response->array, response->size * sizeof( char * ) );
+               }
+
+               /* Make sure the array is valid, or we're really in trouble */
+               if ( response->array == NULL )
+               {
+                       ret = 0;
+                       break;
+               }
+
+               /* Now, if we're appending to the previous write (ie: if it wasn't
+                  terminated by a LF), then use the index calculated above, otherwise
+                  go to the next one and ensure it's NULLed. */
+
+               if ( !response->append )
+               {
+                       response->array[ ++ index ] = NULL;
+                       response->count ++;
+               }
+               else
+               {
+                       length_of_string = strlen( response->array[ index ] );
+               }
+
+               /* Now we need to know how to handle the current ptr with respect to lf. */
+               /* TODO: tidy up and error check... sigh... tested for many, many 1000s of lines */
+
+               if ( lf == NULL )
+               {
+                       response->array[ index ] = realloc( response->array[ index ], length_of_string + size + 1 );
+                       memcpy( response->array[ index ] + length_of_string, ptr, size );
+                       response->array[ index ][ length_of_string + size ] = '\0';
+                       if ( ( length_of_string + size ) > 0 && response->array[ index ][ length_of_string + size - 1 ] == '\r' )
+                               response->array[ index ][ length_of_string + size - 1 ] = '\0';
+                       size = 0;
+                       ret += size;
+                       response->append = 1;
+               }
+               else
+               {
+                       int chars = lf - ptr;
+                       response->array[ index ] = realloc( response->array[ index ], length_of_string + chars + 1 );
+                       memcpy( response->array[ index ] + length_of_string, ptr, chars );
+                       response->array[ index ][ length_of_string + chars ] = '\0';
+                       if ( ( length_of_string + chars ) > 0 && response->array[ index ][ length_of_string + chars - 1 ] == '\r' )
+                               response->array[ index ][ length_of_string + chars - 1 ] = '\0';
+                       ptr = ptr + chars + 1;
+                       size -= ( chars + 1 );
+                       response->append = 0;
+                       ret += chars + 1;
+               }
+       }
+
+       return ret;
+}
+
+/** Close the response.
+*/
+
+void valerie_response_close( valerie_response response )
+{
+       if ( response != NULL )
+       {
+               int index = 0;
+               for ( index = 0; index < response->count; index ++ )
+                       free( response->array[ index ] );
+               free( response->array );
+               free( response );
+       }
+}
diff --git a/mlt/src/valerie/valerie_response.h b/mlt/src/valerie/valerie_response.h
new file mode 100644 (file)
index 0000000..1e8f1fa
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * valerie_response.h -- Response
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_RESPONSE_H_
+#define _VALERIE_RESPONSE_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Structure for the response
+*/
+
+typedef struct
+{
+       char **array;
+       int size;
+       int count;
+       int append;
+}
+*valerie_response, valerie_response_t;
+
+/** API for accessing the response structure.
+*/
+
+extern valerie_response valerie_response_init( );
+extern valerie_response valerie_response_clone( valerie_response );
+extern int valerie_response_get_error_code( valerie_response );
+extern char *valerie_response_get_error_string( valerie_response );
+extern char *valerie_response_get_line( valerie_response, int );
+extern int valerie_response_count( valerie_response );
+extern void valerie_response_set_error( valerie_response, int, char * );
+extern int valerie_response_printf( valerie_response, size_t, char *, ... );
+extern int valerie_response_write( valerie_response, char *, int );
+extern void valerie_response_close( valerie_response );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/valerie/valerie_socket.c b/mlt/src/valerie/valerie_socket.c
new file mode 100644 (file)
index 0000000..74e8483
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * valerie_socket.c -- Client Socket
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* Application header files */
+#include "valerie_socket.h"
+
+/** Initialise the socket.
+*/
+
+valerie_socket valerie_socket_init( char *server, int port )
+{
+       valerie_socket socket = malloc( sizeof( valerie_socket_t ) );
+       if ( socket != NULL )
+       {
+               memset( socket, 0, sizeof( valerie_socket_t ) );
+               socket->fd = -1;
+               socket->server = strdup( server );
+               socket->port = port;
+       }
+       return socket;
+}
+
+/** Connect to the server.
+*/
+
+int valerie_socket_connect( valerie_socket connection )
+{
+       int ret = 0;
+    struct hostent *host;
+    struct sockaddr_in sock;
+
+       if ( connection->server != NULL )
+       {               
+               host = gethostbyname( connection->server );
+       
+               memset( &sock, 0, sizeof( struct sockaddr_in ) );
+               memcpy( &sock.sin_addr, host->h_addr, host->h_length );
+               sock.sin_family = host->h_addrtype;
+               sock.sin_port = htons( connection->port );
+       
+               if ( ( connection->fd = socket( AF_INET, SOCK_STREAM, 0 ) ) != -1 )
+                       ret = connect( connection->fd, (const struct sockaddr *)&sock, sizeof( struct sockaddr_in ) );
+               else
+                       ret = -1;
+       }
+       
+       return ret;     
+}
+
+/** Convenience constructor for a connected file descriptor.
+*/
+
+valerie_socket valerie_socket_init_fd( int fd )
+{
+       valerie_socket socket = malloc( sizeof( valerie_socket_t ) );
+       if ( socket != NULL )
+       {
+               memset( socket, 0, sizeof( valerie_socket_t ) );
+               socket->fd = fd;
+               socket->no_close = 1;
+       }
+       return socket;
+}
+
+/** Read an arbitrarily formatted block of data from the server.
+*/
+
+int valerie_socket_read_data( valerie_socket socket, char *data, int length )
+{
+    struct timeval tv = { 1, 0 };
+    fd_set rfds;
+       int used = 0;
+
+       data[ 0 ] = '\0';
+
+    FD_ZERO( &rfds );
+    FD_SET( socket->fd, &rfds );
+
+       if ( select( socket->fd + 1, &rfds, NULL, NULL, &tv ) )
+       {
+               used = read( socket->fd, data, length - 1 );
+               if ( used > 0 )
+                       data[ used ] = '\0';
+               else
+                       used = -1;
+       }
+
+       return used;
+}      
+
+/** Write an arbitrarily formatted block of data to the server.
+*/
+
+int valerie_socket_write_data( valerie_socket socket, char *data, int length )
+{
+       int used = 0;
+       
+       while ( used >=0 && used < length )
+       {
+               struct timeval tv = { 1, 0 };
+               fd_set rfds;
+               fd_set wfds;
+               fd_set efds;
+       
+               FD_ZERO( &rfds );
+               FD_SET( socket->fd, &rfds );
+               FD_ZERO( &wfds );
+               FD_SET( socket->fd, &wfds );
+               FD_ZERO( &efds );
+               FD_SET( socket->fd, &efds );
+       
+               errno = 0;
+
+               if ( select( socket->fd + 1, &rfds, &wfds, &efds, &tv ) )
+               {
+                       if ( errno != 0 || FD_ISSET( socket->fd, &efds ) || FD_ISSET( socket->fd, &rfds ) )
+                       {
+                               used = -1;
+                       }
+                       else if ( FD_ISSET( socket->fd, &wfds ) )
+                       {
+                               int inc = write( socket->fd, data + used, length - used );
+                               if ( inc > 0 )
+                                       used += inc;
+                               else
+                                       used = -1;
+                       }
+               }
+       }
+
+       return used;
+}
+
+/** Close the socket.
+*/
+
+void valerie_socket_close( valerie_socket socket )
+{
+       if ( socket->fd > 0 && !socket->no_close )
+               close( socket->fd );
+       free( socket->server );
+       free( socket );
+}
diff --git a/mlt/src/valerie/valerie_socket.h b/mlt/src/valerie/valerie_socket.h
new file mode 100644 (file)
index 0000000..f016ca1
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * valerie_socket.h -- Client Socket
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _VALERIE_SOCKET_H_
+#define _VALERIE_SOCKET_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Structure for socket.
+*/
+
+typedef struct
+{
+       char *server;
+       int port;
+       int fd;
+       int no_close;
+}
+*valerie_socket, valerie_socket_t;
+
+/** Remote parser API.
+*/
+
+extern valerie_socket valerie_socket_init( char *, int );
+extern int valerie_socket_connect( valerie_socket );
+extern valerie_socket valerie_socket_init_fd( int );
+extern int valerie_socket_read_data( valerie_socket, char *, int );
+extern int valerie_socket_write_data( valerie_socket, char *, int );
+extern void valerie_socket_close( valerie_socket );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/valerie/valerie_status.c b/mlt/src/valerie/valerie_status.c
new file mode 100644 (file)
index 0000000..5725b0c
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * valerie_status.c -- Unit Status Handling
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Application header files */
+#include "valerie_status.h"
+#include "valerie_tokeniser.h"
+#include "valerie_util.h"
+
+/** Parse a unit status string.
+*/
+
+void valerie_status_parse( valerie_status status, char *text )
+{
+       valerie_tokeniser tokeniser = valerie_tokeniser_init( );
+       if ( valerie_tokeniser_parse_new( tokeniser, text, " " ) == 17 )
+       {
+               status->unit = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) );
+               strncpy( status->clip, valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 2 ), '\"' ), sizeof( status->clip ) );
+               status->position = atof( valerie_tokeniser_get_string( tokeniser, 3 ) );
+               status->speed = atoi( valerie_tokeniser_get_string( tokeniser, 4 ) );
+               status->fps = atof( valerie_tokeniser_get_string( tokeniser, 5 ) );
+               status->in = atof( valerie_tokeniser_get_string( tokeniser, 6 ) );
+               status->out = atof( valerie_tokeniser_get_string( tokeniser, 7 ) );
+               status->length = atof( valerie_tokeniser_get_string( tokeniser, 8 ) );
+
+               strncpy( status->tail_clip, valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 9 ), '\"' ), sizeof( status->tail_clip ) );
+               status->tail_position = atof( valerie_tokeniser_get_string( tokeniser, 10 ) );
+               status->tail_in = atof( valerie_tokeniser_get_string( tokeniser, 11 ) );
+               status->tail_out = atof( valerie_tokeniser_get_string( tokeniser, 12 ) );
+               status->tail_length = atof( valerie_tokeniser_get_string( tokeniser, 13 ) );
+               status->seek_flag = atof( valerie_tokeniser_get_string( tokeniser, 14 ) );
+               status->generation = atof( valerie_tokeniser_get_string( tokeniser, 15 ) );
+               status->clip_index = atof( valerie_tokeniser_get_string( tokeniser, 16 ) );
+
+               if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "unknown" ) )
+                       status->status = unit_unknown;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "undefined" ) )
+                       status->status = unit_undefined;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "offline" ) )
+                       status->status = unit_offline;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "not_loaded" ) )
+                       status->status = unit_not_loaded;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "stopped" ) )
+                       status->status = unit_stopped;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "paused" ) )
+                       status->status = unit_paused;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "playing" ) )
+                       status->status = unit_playing;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "disconnected" ) )
+                       status->status = unit_disconnected;
+       }
+       else
+       {
+               memset( status, 0, sizeof( valerie_status_t ) );
+               fprintf( stderr, "Status thread changed?\n" );
+       }
+       valerie_tokeniser_close( tokeniser );
+}
+
+/** Serialise a status into a string.
+*/
+
+char *valerie_status_serialise( valerie_status status, char *text, int length )
+{
+       char *status_string = NULL;
+
+       switch( status->status )
+       {
+               case unit_undefined:
+                       status_string = "undefined";
+                       break;
+
+               case unit_offline:
+                       status_string = "offline";
+                       break;
+
+               case unit_not_loaded:
+                       status_string = "not_loaded";
+                       break;
+
+               case unit_stopped:
+                       status_string = "stopped";
+                       break;
+
+               case unit_playing:
+                       status_string = "playing";
+                       break;
+
+               case unit_unknown:
+                       status_string = "unknown";
+                       break;
+
+               case unit_paused:
+                       status_string = "paused";
+                       break;
+
+               case unit_disconnected:
+                       status_string = "disconnected";
+                       break;
+       }
+
+       snprintf( text, length, "%d %s \"%s\" %e %e %.2f %e %e %e \"%s\" %e %e %e %e %d %d %d\r\n",
+                                                       status->unit,
+                                                       status_string,
+                                                       status->clip,
+                                                       status->position, 
+                                                       status->speed,
+                                                       status->fps,
+                                                       status->in,
+                                                       status->out,
+                                                       status->length,
+                                                       status->tail_clip,
+                                                       status->tail_position, 
+                                                       status->tail_in,
+                                                       status->tail_out,
+                                                       status->tail_length,
+                                                       status->seek_flag,
+                                                       status->generation,
+                                                       status->clip_index );
+
+       return text;
+}
+
+/** Compare two status codes for changes.
+*/
+
+int valerie_status_compare( valerie_status status1, valerie_status status2 )
+{
+       return memcmp( status1, status2, sizeof( valerie_status_t ) );
+}
+
+/** Copy status code info from dest to src.
+*/
+
+valerie_status valerie_status_copy( valerie_status dest, valerie_status src )
+{
+       return memcpy( dest, src, sizeof( valerie_status_t ) );
+}
diff --git a/mlt/src/valerie/valerie_status.h b/mlt/src/valerie/valerie_status.h
new file mode 100644 (file)
index 0000000..d0e45a9
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * valerie_status.h -- Unit Status Handling
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_STATUS_H_
+#define _VALERIE_STATUS_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Status codes
+*/
+
+typedef enum
+{
+       unit_unknown = 0,
+       unit_undefined,
+       unit_offline,
+       unit_not_loaded,
+       unit_stopped,
+       unit_playing,
+       unit_paused,
+       unit_disconnected
+}
+unit_status;
+
+/** Status structure.
+*/
+
+typedef struct
+{
+       int unit;
+       unit_status status;
+       char clip[ 2048 ];
+       double position;
+       double speed;
+       double fps;
+       double in;
+       double out;
+       double length;
+       char tail_clip[ 2048 ];
+       double tail_position;
+       double tail_in;
+       double tail_out;
+       double tail_length;
+       int seek_flag;
+       int generation;
+       int clip_index;
+       int dummy;
+}
+*valerie_status, valerie_status_t;
+
+/** DV1394 Status API
+*/
+
+extern void valerie_status_parse( valerie_status, char * );
+extern char *valerie_status_serialise( valerie_status, char *, int );
+extern int valerie_status_compare( valerie_status, valerie_status );
+extern valerie_status valerie_status_copy( valerie_status, valerie_status );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/valerie/valerie_tokeniser.c b/mlt/src/valerie/valerie_tokeniser.c
new file mode 100644 (file)
index 0000000..7acaf85
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * valerie_tokeniser.c -- String tokeniser
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <stdlib.h>
+#include <string.h>
+
+/* Application header files */
+#include "valerie_tokeniser.h"
+
+/** Initialise a tokeniser.
+*/
+
+valerie_tokeniser valerie_tokeniser_init( )
+{
+       valerie_tokeniser tokeniser = malloc( sizeof( valerie_tokeniser_t ) );
+       if ( tokeniser != NULL )
+               memset( tokeniser, 0, sizeof( valerie_tokeniser_t ) );
+       return tokeniser;
+}
+
+/** Clear the tokeniser.
+*/
+
+static void valerie_tokeniser_clear( valerie_tokeniser tokeniser )
+{
+       int index = 0;
+       for ( index = 0; index < tokeniser->count; index ++ )
+               free( tokeniser->tokens[ index ] );
+       tokeniser->count = 0;
+       free( tokeniser->input );
+       tokeniser->input = NULL;
+}
+
+/** Append a string to the tokeniser.
+*/
+
+static int valerie_tokeniser_append( valerie_tokeniser tokeniser, char *token )
+{
+       int error = 0;
+
+       if ( tokeniser->count == tokeniser->size )
+       {
+               tokeniser->size += 20;
+               tokeniser->tokens = realloc( tokeniser->tokens, tokeniser->size * sizeof( char * ) );
+       }
+
+       if ( tokeniser->tokens != NULL )
+       {
+               tokeniser->tokens[ tokeniser->count ++ ] = strdup( token );
+       }
+       else
+       {
+               tokeniser->count = 0;
+               error = -1;
+       }
+       return error;
+}
+
+/** Parse a string by splitting on the delimiter provided.
+*/
+
+int valerie_tokeniser_parse_new( valerie_tokeniser tokeniser, char *string, char *delimiter )
+{
+       int count = 0;
+       int length = strlen( string );
+       int delimiter_size = strlen( delimiter );
+       int index = 0;
+       char *token = strdup( string );
+
+       valerie_tokeniser_clear( tokeniser );
+       tokeniser->input = strdup( string );
+       strcpy( token, "" );
+
+       for ( index = 0; index < length; )
+       {
+               char *start = string + index;
+               char *end = strstr( start, delimiter );
+
+               if ( end == NULL )
+               {
+                       strcat( token, start );
+                       valerie_tokeniser_append( tokeniser, token );
+                       index = length;
+                       count ++;
+               }
+               else if ( start != end )
+               {
+                       strncat( token, start, end - start );
+                       index += end - start;
+                       if ( token[ 0 ] != '\"' || ( token[ 0 ] == '\"' && token[ strlen( token ) - 1 ] == '\"' ) )
+                       {
+                               valerie_tokeniser_append( tokeniser, token );
+                               strcpy( token, "" );
+                               count ++;
+                       }
+                       else while ( strncmp( string + index, delimiter, delimiter_size ) == 0 )
+                       {
+                               strncat( token, delimiter, delimiter_size );
+                               index += delimiter_size;
+                       }
+               }
+               else
+               {
+                       index += strlen( delimiter );
+               }
+       }
+
+       /* Special case - malformed string condition */
+       if ( !strcmp( token, "" ) )
+       {
+               count = 0 - ( count - 1 );
+               valerie_tokeniser_append( tokeniser, token );
+       }
+               
+       free( token );
+       return count;
+}
+
+/** Get the original input.
+*/
+
+char *valerie_tokeniser_get_input( valerie_tokeniser tokeniser )
+{
+       return tokeniser->input;
+}
+
+/** Get the number of tokens.
+*/
+
+int valerie_tokeniser_count( valerie_tokeniser tokeniser )
+{
+       return tokeniser->count;
+}
+
+/** Get a token as a string.
+*/
+
+char *valerie_tokeniser_get_string( valerie_tokeniser tokeniser, int index )
+{
+       if ( index < tokeniser->count )
+               return tokeniser->tokens[ index ];
+       else
+               return NULL;
+}
+
+/** Close the tokeniser.
+*/
+
+void valerie_tokeniser_close( valerie_tokeniser tokeniser )
+{
+       valerie_tokeniser_clear( tokeniser );
+       free( tokeniser->tokens );
+       free( tokeniser );
+}
diff --git a/mlt/src/valerie/valerie_tokeniser.h b/mlt/src/valerie/valerie_tokeniser.h
new file mode 100644 (file)
index 0000000..9d0838c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * valerie_tokeniser.h -- String tokeniser
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_TOKENISER_H_
+#define _VALERIE_TOKENISER_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Structure for tokeniser.
+*/
+
+typedef struct
+{
+       char *input;
+       char **tokens;
+       int count;
+       int size;
+}
+*valerie_tokeniser, valerie_tokeniser_t;
+
+/** Remote parser API.
+*/
+
+extern valerie_tokeniser valerie_tokeniser_init( );
+extern int valerie_tokeniser_parse_new( valerie_tokeniser, char *, char * );
+extern char *valerie_tokeniser_get_input( valerie_tokeniser );
+extern int valerie_tokeniser_count( valerie_tokeniser );
+extern char *valerie_tokeniser_get_string( valerie_tokeniser, int );
+extern void valerie_tokeniser_close( valerie_tokeniser );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mlt/src/valerie/valerie_util.c b/mlt/src/valerie/valerie_util.c
new file mode 100644 (file)
index 0000000..168f6a7
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * valerie_util.c -- General Purpose Client Utilities
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <string.h>
+#include <ctype.h>
+
+/* Application header files */
+#include "valerie_util.h"
+
+/** Remove LF or CR/LF terminations from the input string.
+*/
+
+char *valerie_util_chomp( char *input )
+{
+       if ( input != NULL )
+       {
+               int length = strlen( input );
+               if ( length && input[ length - 1 ] == '\n' )
+                       input[ length - 1 ] = '\0';
+               if ( length > 1 && input[ length - 2 ] == '\r' )
+                       input[ length - 2 ] = '\0';
+       }
+       return input;
+}
+
+/** Remove leading and trailing spaces from the input string.
+*/
+
+char *valerie_util_trim( char *input )
+{
+       if ( input != NULL )
+       {
+               int length = strlen( input );
+               int first = 0;
+               while( first < length && isspace( input[ first ] ) )
+                       first ++;
+               memmove( input, input + first, length - first + 1 );
+               length = length - first;
+               while ( length > 0 && isspace( input[ length - 1 ] ) )
+                       input[ -- length ] = '\0';
+       }
+       return input;
+}
+
+/** Strip the specified string of leading and trailing 'value' (ie: ").
+*/
+
+char *valerie_util_strip( char *input, char value )
+{
+       if ( input != NULL )
+       {
+               char *ptr = strrchr( input, value );
+               if ( ptr != NULL )
+                       *ptr = '\0';
+               if ( input[ 0 ] == value )
+                       strcpy( input, input + 1 );
+       }
+       return input;
+}
diff --git a/mlt/src/valerie/valerie_util.h b/mlt/src/valerie/valerie_util.h
new file mode 100644 (file)
index 0000000..492eba0
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * valerie_util.h -- General Purpose Client Utilities
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_UTIL_H_
+#define _VALERIE_UTIL_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+extern char *valerie_util_chomp( char * );
+extern char *valerie_util_trim( char * );
+extern char *valerie_util_strip( char *, char );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/framework/Makefile b/src/framework/Makefile
new file mode 100644 (file)
index 0000000..e2d60ee
--- /dev/null
@@ -0,0 +1,38 @@
+
+FRAMEWORK_OBJS = mlt_frame.o \
+                                mlt_property.o \
+                                mlt_properties.o \
+                                mlt_service.o \
+                                mlt_producer.o \
+                                mlt_multitrack.o \
+                                mlt_consumer.o \
+                                mlt_filter.o \
+                                mlt_transition.o \
+                                mlt_tractor.o \
+                                mlt_factory.o \
+                                mlt_repository.o
+
+OBJS = $(FRAMEWORK_OBJS)
+
+SRCS := $(OBJS:.o=.c)
+
+CFLAGS=-g -Wall -D_FILE_OFFSET_BITS=64 -pthread 
+
+all:   libmlt.a
+
+libmlt.a: $(OBJS)
+               $(AR) rvu $@ $(OBJS)
+               ranlib $@
+
+depend:        $(SRCS)
+               $(CC) -MM $(CFLAGS) $^ 1>.depend
+
+dist-clean:    clean
+               rm -f .depend
+
+clean: 
+               rm -f $(FRAMEWORK_OBJS) libmlt.a
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/src/framework/config.h b/src/framework/config.h
new file mode 100644 (file)
index 0000000..fec9861
--- /dev/null
@@ -0,0 +1,10 @@
+/** GENERATED FILE - DON'T EDIT */
+
+#ifndef _MLT_CONFIG_H_
+#define _MLT_CONFIG_H_
+
+#define PREFIX                 "/usr/local"
+#define PREFIX_DATA            PREFIX "/share"
+
+#endif
+
diff --git a/src/framework/configure b/src/framework/configure
new file mode 100755 (executable)
index 0000000..a9bf588
--- /dev/null
@@ -0,0 +1 @@
+#!/bin/bash
diff --git a/src/framework/mlt_consumer.c b/src/framework/mlt_consumer.c
new file mode 100644 (file)
index 0000000..635ad65
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * mlt_consumer.c -- abstraction for all consumer services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "mlt_consumer.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/** Public final methods
+*/
+
+int mlt_consumer_init( mlt_consumer this, void *child )
+{
+       memset( this, 0, sizeof( struct mlt_consumer_s ) );
+       this->child = child;
+       return mlt_service_init( &this->parent, this );
+}
+
+/** Get the parent service object.
+*/
+
+mlt_service mlt_consumer_service( mlt_consumer this )
+{
+       return &this->parent;
+}
+
+/** 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 );
+}
+
+/** Close the consumer.
+*/
+
+void mlt_consumer_close( mlt_consumer this )
+{
+       if ( this->close != NULL )
+               this->close( this );
+       else
+               mlt_service_close( &this->parent );
+}
+
diff --git a/src/framework/mlt_consumer.h b/src/framework/mlt_consumer.h
new file mode 100644 (file)
index 0000000..cbe9078
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * mlt_consumer.h -- abstraction for all consumer services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_CONSUMER_H_
+#define _MLT_CONSUMER_H_
+
+#include "mlt_service.h"
+
+/** The interface definition for all consumers.
+*/
+
+struct mlt_consumer_s
+{
+       // We're implementing service here
+       struct mlt_service_s parent;
+
+       // public virtual
+       void ( *close )( mlt_consumer );
+
+       // Private data
+       void *private;
+       void *child;
+};
+
+/** Public final methods
+*/
+
+extern int mlt_consumer_init( mlt_consumer this, void *child );
+extern mlt_service mlt_consumer_service( mlt_consumer this );
+extern int mlt_consumer_connect( mlt_consumer this, mlt_service producer );
+extern void mlt_consumer_close( mlt_consumer );
+
+#endif
diff --git a/src/framework/mlt_factory.c b/src/framework/mlt_factory.c
new file mode 100644 (file)
index 0000000..3b40464
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * mlt_factory.c -- the factory method interfaces
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "mlt_factory.h"
+#include "mlt_repository.h"
+
+#include <stdlib.h>
+
+/** Singleton repositories
+*/
+
+static mlt_repository producers = NULL;
+static mlt_repository filters = NULL;
+static mlt_repository transitions = NULL;
+static mlt_repository consumers = NULL;
+
+/** Construct the factories.
+*/
+
+int mlt_factory_init( )
+{
+       producers = mlt_repository_init( PREFIX_DATA "/producers.dat", "mlt_create_producer" );
+       filters = mlt_repository_init( PREFIX_DATA "/filters.dat", "mlt_create_filter" );
+       transitions = mlt_repository_init( PREFIX_DATA "/transitions.dat", "mlt_create_transition" );
+       consumers = mlt_repository_init( PREFIX_DATA "/consumers.dat", "mlt_create_consumer" );
+       return 0;
+}
+
+/** Fetch a producer from the repository.
+*/
+
+mlt_producer mlt_factory_producer( char *service, void *input )
+{
+       return ( mlt_producer )mlt_repository_fetch( producers, service, input );
+}
+
+/** Fetch a filter from the repository.
+*/
+
+mlt_filter mlt_factory_filter( char *service, void *input )
+{
+       return ( mlt_filter )mlt_repository_fetch( filters, service, input );
+}
+
+/** Fetch a transition from the repository.
+*/
+
+mlt_transition mlt_transition_filter( char *service, void *input )
+{
+       return ( mlt_transition )mlt_repository_fetch( transitions, service, input );
+}
+
+/** Fetch a consumer from the repository
+*/
+
+mlt_consumer mlt_factory_consumer( char *service, void *input )
+{
+       return ( mlt_consumer )mlt_repository_fetch( consumers, service, input );
+}
+
+/** Close the factory.
+*/
+
+void mlt_factory_close( )
+{
+       mlt_repository_close( producers );
+       mlt_repository_close( filters );
+       mlt_repository_close( transitions );
+       mlt_repository_close( consumers );
+}
+
diff --git a/src/framework/mlt_factory.h b/src/framework/mlt_factory.h
new file mode 100644 (file)
index 0000000..4cece1d
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * mlt_factory.h -- the factory method interfaces
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_FACTORY_H
+#define _MLT_FACTORY_H
+
+#include "mlt_types.h"
+
+extern int mlt_factory_init( );
+extern mlt_producer mlt_factory_producer( char *name, void *input );
+extern mlt_filter mlt_factory_filter( char *name, void *input );
+extern mlt_transition mlt_factory_transition( char *name, void *input );
+extern mlt_consumer mlt_factory_consumer( char *name, void *input );
+extern void mlt_factory_close( );
+
+#endif
diff --git a/src/framework/mlt_filter.c b/src/framework/mlt_filter.c
new file mode 100644 (file)
index 0000000..22fefe2
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * mlt_filter.c -- abstraction for all filter services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 )
+       {
+               service->get_frame = filter_get_frame;
+               return 0;
+       }
+       return 1;
+}
+
+/** Get the service associated to this filter
+*/
+
+mlt_service mlt_filter_service( mlt_filter this )
+{
+       return &this->parent;
+}
+
+/** 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 )
+       {
+               this->producer = producer;
+               this->track = index;
+               this->in = 0;
+               this->out = 0;
+       }
+       
+       return ret;
+}
+
+/** Tune the in/out points.
+*/
+
+void mlt_filter_set_in_and_out( mlt_filter this, mlt_timecode in, mlt_timecode out )
+{
+       this->in = in;
+       this->out = out;
+}
+
+/** Return the track that this filter is operating on.
+*/
+
+int mlt_filter_get_track( mlt_filter this )
+{
+       return this->track;
+}
+
+/** Get the in point.
+*/
+
+mlt_timecode mlt_filter_get_in( mlt_filter this )
+{
+       return this->in;
+}
+
+/** Get the out point.
+*/
+
+mlt_timecode mlt_filter_get_out( mlt_filter this )
+{
+       return this->out;
+}
+
+/** Process the frame.
+*/
+
+static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
+{
+       if ( 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;
+       
+       // If the frame request is for this filters track, we need to process it
+       if ( index == this->track )
+       {
+               int ret = mlt_service_get_frame( this->producer, frame, index );
+               if ( ret == 0 )
+               {
+                       if ( !mlt_frame_is_test_card( *frame ) )
+                       {
+                               mlt_timecode timecode = mlt_frame_get_timecode( *frame );
+                               if ( timecode >= this->in && ( this->out == 0 || timecode < this->out ) )
+                                       *frame = filter_process( this, *frame );
+                       }
+                       return 0;
+               }
+               else
+               {
+                       *frame = mlt_frame_init( );
+                       return 0;
+               }
+       }
+       else
+       {
+               return mlt_service_get_frame( this->producer, frame, index );
+       }
+}
+
+/** Close the filter.
+*/
+
+void mlt_filter_close( mlt_filter this )
+{
+       if ( this->close != NULL )
+               this->close( this );
+       else
+               mlt_service_close( &this->parent );
+}
+
diff --git a/src/framework/mlt_filter.h b/src/framework/mlt_filter.h
new file mode 100644 (file)
index 0000000..99212a9
--- /dev/null
@@ -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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 );
+
+       // track and in/out points
+       mlt_service producer;
+       int track;
+       mlt_timecode in;
+       mlt_timecode out;
+
+       // Protected
+       void *child;
+};
+
+/** Public final methods
+*/
+
+extern int mlt_filter_init( mlt_filter this, void *child );
+extern mlt_service mlt_filter_service( mlt_filter this );
+extern int mlt_filter_connect( mlt_filter this, mlt_service producer, int index );
+extern void mlt_filter_set_in_and_out( mlt_filter this, mlt_timecode in, mlt_timecode out );
+extern int mlt_filter_get_track( mlt_filter this );
+extern mlt_timecode mlt_filter_get_in( mlt_filter this );
+extern mlt_timecode mlt_filter_get_out( mlt_filter this );
+extern void mlt_filter_close( mlt_filter );
+
+#endif
diff --git a/src/framework/mlt_frame.c b/src/framework/mlt_frame.c
new file mode 100644 (file)
index 0000000..9c9eac1
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * mlt_frame.c -- interface for all frame classes
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "mlt_frame.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct
+{
+       mlt_image_format vfmt;
+       int width;
+       int height;
+       uint8_t *image;
+       uint8_t *alpha;
+       mlt_audio_format afmt;
+       int16_t *audio;
+}
+frame_test;
+
+static frame_test test_card = { mlt_image_none, 0, 0, NULL, NULL, mlt_audio_none, NULL };
+
+/** Constructor for a frame.
+*/
+
+mlt_frame mlt_frame_init( )
+{
+       // Allocate a frame
+       mlt_frame this = calloc( sizeof( struct mlt_frame_s ), 1 );
+
+       if ( this != NULL )
+       {
+               // Initialise the properties
+               mlt_properties properties = &this->parent;
+               mlt_properties_init( properties, this );
+
+               // Set default properties on the frame
+               mlt_properties_set_timecode( properties, "timecode", 0.0 );
+               mlt_properties_set_data( properties, "image", NULL, 0, NULL, NULL );
+               mlt_properties_set_int( properties, "width", 720 );
+               mlt_properties_set_int( properties, "height", 576 );
+               mlt_properties_set_double( properties, "aspect_ratio", 4.0 / 3.0 );
+               mlt_properties_set_data( properties, "audio", NULL, 0, NULL, NULL );
+               mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL );
+       }
+       return this;
+}
+
+/** Fetch the frames properties.
+*/
+
+mlt_properties mlt_frame_properties( mlt_frame this )
+{
+       return &this->parent;
+}
+
+/** Check if we have a way to derive something other than a test card.
+*/
+
+int mlt_frame_is_test_card( mlt_frame this )
+{
+       return this->stack_get_image_size == 0;
+}
+
+/** Get the aspect ratio of the frame.
+*/
+
+double mlt_frame_get_aspect_ratio( mlt_frame this )
+{
+       mlt_properties properties = mlt_frame_properties( this );
+       return mlt_properties_get_double( properties, "aspect_ratio" );
+}
+
+/** Set the aspect ratio of the frame.
+*/
+
+int mlt_frame_set_aspect_ratio( mlt_frame this, double value )
+{
+       mlt_properties properties = mlt_frame_properties( this );
+       return mlt_properties_set_double( properties, "aspect_ratio", value );
+}
+
+/** Get the timecode of this frame.
+*/
+
+mlt_timecode mlt_frame_get_timecode( mlt_frame this )
+{
+       mlt_properties properties = mlt_frame_properties( this );
+       return mlt_properties_get_timecode( properties, "timecode" );
+}
+
+/** Set the timecode of this frame.
+*/
+
+int mlt_frame_set_timecode( mlt_frame this, mlt_timecode value )
+{
+       mlt_properties properties = mlt_frame_properties( this );
+       return mlt_properties_set_timecode( properties, "timecode", value );
+}
+
+/** Stack a get_image callback.
+*/
+
+int mlt_frame_push_get_image( mlt_frame this, mlt_get_image get_image )
+{
+       int ret = this->stack_get_image_size >= 10;
+       if ( ret == 0 )
+               this->stack_get_image[ this->stack_get_image_size ++ ] = get_image;
+       return ret;
+}
+
+/** Pop a get_image callback.
+*/
+
+mlt_get_image mlt_frame_pop_get_image( mlt_frame this )
+{
+       mlt_get_image result = NULL;
+       if ( this->stack_get_image_size > 0 )
+               result = this->stack_get_image[ -- this->stack_get_image_size ];
+       return result;
+}
+
+/** Push a frame.
+*/
+
+int mlt_frame_push_frame( mlt_frame this, mlt_frame that )
+{
+       int ret = this->stack_frame_size >= 10;
+       if ( ret == 0 )
+               this->stack_frame[ this->stack_frame_size ++ ] = that;
+       return ret;
+}
+
+/** Pop a frame.
+*/
+
+mlt_frame mlt_frame_pop_frame( mlt_frame this )
+{
+       mlt_frame result = NULL;
+       if ( this->stack_frame_size > 0 )
+               result = this->stack_frame[ -- this->stack_frame_size ];
+       return result;
+}
+
+int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
+{
+       mlt_properties properties = mlt_frame_properties( this );
+       mlt_get_image get_image = mlt_frame_pop_get_image( this );
+       
+       if ( get_image != NULL )
+       {
+               return get_image( this, buffer, format, width, height, writable );
+       }
+       else if ( mlt_properties_get_data( properties, "image", NULL ) != NULL )
+       {
+               *format = mlt_image_yuv422;
+               *buffer = mlt_properties_get_data( properties, "image", NULL );
+               *width = mlt_properties_get_int( properties, "width" );
+               *height = mlt_properties_get_int( properties, "height" );
+       }
+       else
+       {
+               if ( test_card.vfmt != *format )
+               {
+                       uint8_t *p;
+                       uint8_t *q;
+                       
+                       test_card.vfmt = *format;
+                       test_card.width = 720;
+                       test_card.height = 576;
+
+                       switch( *format )
+                       {
+                               case mlt_image_none:
+                                       break;
+                               case mlt_image_rgb24:
+                                       test_card.image = realloc( test_card.image, test_card.width * test_card.height * 3 );
+                                       memset( test_card.image, 255, test_card.width * test_card.height * 3 );
+                                       break;
+                               case mlt_image_rgb24a:
+                                       test_card.image = realloc( test_card.image, test_card.width * test_card.height * 4 );
+                                       memset( test_card.image, 255, test_card.width * test_card.height * 4 );
+                                       break;
+                               case mlt_image_yuv422:
+                                       test_card.image = realloc( test_card.image, test_card.width * test_card.height * 2 );
+                                       p = test_card.image;
+                                       q = test_card.image + test_card.width * test_card.height * 2;
+                                       while ( p != q )
+                                       {
+                                               *p ++ = 255;
+                                               *p ++ = 128;
+                                       }
+                                       break;
+                               case mlt_image_yuv420p:
+                                       test_card.image = realloc( test_card.image, test_card.width * test_card.height * 3 / 2 );
+                                       memset( test_card.image, 255, test_card.width * test_card.height * 3 / 2 );
+                                       break;
+                       }
+               }
+
+               *width = test_card.width;
+               *height = test_card.height;
+               *buffer = test_card.image;
+       }
+
+       return 0;
+}
+
+uint8_t *mlt_frame_get_alpha_mask( mlt_frame this )
+{
+       if ( this->get_alpha_mask != NULL )
+               return this->get_alpha_mask( this );
+       return test_card.alpha;
+}
+
+int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
+{
+       if ( this->get_audio != NULL )
+       {
+               return this->get_audio( this, buffer, format, frequency, channels, samples );
+       }
+       else
+       {
+               if ( test_card.afmt != *format )
+               {
+                       test_card.afmt = *format;
+                       test_card.audio = realloc( test_card.audio, 1920 * 2 * sizeof( int16_t ) );
+                       memset( test_card.audio, 0, 1920 * 2 * sizeof( int16_t ) );
+               }
+               
+               *buffer = test_card.audio;
+               *frequency = 48000;
+               *channels = 2;
+               *samples = 1920;
+       }
+       return 0;
+}
+
+void mlt_frame_close( mlt_frame this )
+{
+       mlt_frame frame = mlt_frame_pop_frame( this );
+       
+       while ( frame != NULL )
+       {
+               mlt_frame_close( frame);
+               frame = mlt_frame_pop_frame( this );
+       }
+       
+       mlt_properties_close( &this->parent );
+
+       free( this );
+}
+
+/***** convenience functions *****/
+#define RGB2YUV(r, g, b, y, u, v)\
+  y = (306*r + 601*g + 117*b)  >> 10;\
+  u = ((-172*r - 340*g + 512*b) >> 10)  + 128;\
+  v = ((512*r - 429*g - 83*b) >> 10) + 128;\
+  y = y < 0 ? 0 : y;\
+  u = u < 0 ? 0 : u;\
+  v = v < 0 ? 0 : v;\
+  y = y > 255 ? 255 : y;\
+  u = u > 255 ? 255 : u;\
+  v = v > 255 ? 255 : v
+
+int mlt_convert_rgb24a_to_yuv422( uint8_t *rgba, int width, int height, int stride, uint8_t *yuv, uint8_t *alpha )
+{
+       int ret = 0;
+       register int y0, y1, u0, u1, v0, v1;
+       register int r, g, b;
+       register uint8_t *d = yuv;
+       register int i, j;
+
+       for ( i = 0; i < height; i++ )
+       {
+               register uint8_t *s = rgba + ( stride * i );
+               for ( j = 0; j < ( width / 2 ); j++ )
+               {
+                       r = *s++;
+                       g = *s++;
+                       b = *s++;
+                       *alpha++ = *s++;
+                       RGB2YUV (r, g, b, y0, u0 , v0);
+                       r = *s++;
+                       g = *s++;
+                       b = *s++;
+                       *alpha++ = *s++;
+                       RGB2YUV (r, g, b, y1, u1 , v1);
+                       *d++ = y0;
+                       *d++ = (u0+u1) >> 1;
+                       *d++ = y1;
+                       *d++ = (v0+v1) >> 1;
+               }
+       }
+       return ret;
+}
+
+int mlt_convert_rgb24_to_yuv422( uint8_t *rgb, int width, int height, int stride, uint8_t *yuv )
+{
+       int ret = 0;
+       register int y0, y1, u0, u1, v0, v1;
+       register int r, g, b;
+       register uint8_t *d = yuv;
+       register int i, j;
+
+       for ( i = 0; i < height; i++ )
+       {
+               register uint8_t *s = rgb + ( stride * i );
+               for ( j = 0; j < ( width / 2 ); j++ )
+               {
+                       r = *s++;
+                       g = *s++;
+                       b = *s++;
+                       RGB2YUV (r, g, b, y0, u0 , v0);
+                       r = *s++;
+                       g = *s++;
+                       b = *s++;
+                       RGB2YUV (r, g, b, y1, u1 , v1);
+                       *d++ = y0;
+                       *d++ = (u0+u1) >> 1;
+                       *d++ = y1;
+                       *d++ = (v0+v1) >> 1;
+               }
+       }
+       return ret;
+}
+
+int mlt_frame_composite_yuv( mlt_frame this, mlt_frame that, int x, int y, float weight )
+{
+       int ret = 0;
+       int x_start = 0;
+       int width_src, height_src;
+       int width_dest, height_dest;
+       mlt_image_format format_src, format_dest;
+       uint8_t *p_src, *p_dest;
+       int x_end;
+       int i, j;
+       int stride_src;
+       int stride_dest;
+
+       format_src = mlt_image_yuv422;
+       format_dest = mlt_image_yuv422;
+       
+       mlt_frame_get_image( this, &p_dest, &format_dest, &width_dest, &height_dest, 1 /* writable */ );
+       mlt_frame_get_image( that, &p_src, &format_src, &width_src, &height_src, 0 /* writable */ );
+       
+       x_end = width_src;
+       
+       stride_src = width_src * 2;
+       stride_dest = width_dest * 2;
+       uint8_t *lower = p_dest;
+       uint8_t *upper = p_dest + height_dest * stride_dest;
+
+       p_dest += ( y * stride_dest ) + ( x * 2 );
+
+       if ( x < 0 )
+       {
+               x_start = -x;
+               x_end += x_start;
+       }
+
+       uint8_t *z = mlt_frame_get_alpha_mask( that );
+
+       for ( i = 0; i < height_src; i++ )
+       {
+               uint8_t *p = p_src;
+               uint8_t *q = p_dest;
+               uint8_t *o = p_dest;
+
+               for ( j = 0; j < width_src; j ++ )
+               {
+                       if ( q >= lower && q < upper && j >= x_start && j < x_end )
+                       {
+                               uint8_t y = *p ++;
+                               uint8_t uv = *p ++;
+                               uint8_t a = ( z == NULL ) ? 255 : *z ++;
+                               float value = ( weight * ( float ) a / 255.0 );
+                               *o ++ = (uint8_t)( y * value + *q++ * ( 1 - value ) );
+                               *o ++ = (uint8_t)( uv * value + *q++ * ( 1 - value ) );
+                       }
+                       else
+                       {
+                               p += 2;
+                               o += 2;
+                               q += 2;
+                               if ( z != NULL )
+                                       z += 1;
+                       }
+               }
+
+               p_src += stride_src;
+               p_dest += stride_dest;
+       }
+
+       return ret;
+}
+
diff --git a/src/framework/mlt_frame.h b/src/framework/mlt_frame.h
new file mode 100644 (file)
index 0000000..fd86f23
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * mlt_frame.h -- interface for all frame classes
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_FRAME_H_
+#define _MLT_FRAME_H_
+
+#include "mlt_properties.h"
+
+typedef enum
+{
+       mlt_image_none = 0,
+       mlt_image_rgb24,
+       mlt_image_rgb24a,
+       mlt_image_yuv422,
+       mlt_image_yuv420p
+}
+mlt_image_format;
+
+typedef enum
+{
+       mlt_audio_none = 0,
+       mlt_audio_pcm
+}
+mlt_audio_format;
+
+typedef int ( *mlt_get_image )( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable );
+
+struct mlt_frame_s
+{
+       // We're extending properties here
+       struct mlt_properties_s parent;
+
+       // Virtual methods
+       int ( *get_audio )( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
+       uint8_t * ( *get_alpha_mask )( mlt_frame this );
+       
+       // Private properties
+       mlt_get_image stack_get_image[ 10 ];
+       int stack_get_image_size;
+       mlt_frame stack_frame[ 10 ];
+       int stack_frame_size;
+};
+
+extern mlt_frame mlt_frame_init( );
+extern mlt_properties mlt_frame_properties( mlt_frame this );
+extern int mlt_frame_is_test_card( mlt_frame this );
+extern double mlt_frame_get_aspect_ratio( mlt_frame this );
+extern int mlt_frame_set_aspect_ratio( mlt_frame this, double value );
+extern mlt_timecode mlt_frame_get_timecode( mlt_frame this );
+extern int mlt_frame_set_timecode( mlt_frame this, mlt_timecode value );
+
+extern int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable );
+extern uint8_t *mlt_frame_get_alpha_mask( mlt_frame this );
+extern int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
+
+extern int mlt_frame_push_get_image( mlt_frame this, mlt_get_image get_image );
+extern mlt_get_image mlt_frame_pop_get_image( mlt_frame this );
+extern int mlt_frame_push_frame( mlt_frame this, mlt_frame that );
+extern mlt_frame mlt_frame_pop_frame( mlt_frame this );
+extern void mlt_frame_close( mlt_frame this );
+
+/* convenience functions */
+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_frame_composite_yuv( mlt_frame this, mlt_frame that, int x, int y, float weight );
+    
+#endif
+
diff --git a/src/framework/mlt_manager.h b/src/framework/mlt_manager.h
new file mode 100644 (file)
index 0000000..1567e64
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * mlt_manager.h -- manager service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_MANAGER_H_
+#define _MLT_MANAGER_H_
+
+mlt_producer mlt_manager_init( char **config );
+
+#endif
diff --git a/src/framework/mlt_multitrack.c b/src/framework/mlt_multitrack.c
new file mode 100644 (file)
index 0000000..77158c7
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * mlt_multitrack.c -- multitrack service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "mlt_multitrack.h"
+#include "mlt_frame.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/** Private definition.
+*/
+
+struct mlt_multitrack_s
+{
+       // We're extending producer here
+       struct mlt_producer_s parent;
+       mlt_producer *list;
+       int size;
+       int count;
+};
+
+/** Forward reference.
+*/
+
+static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index );
+
+/** Constructor.
+*/
+
+mlt_multitrack mlt_multitrack_init( )
+{
+       // Allocate the multitrack object
+       mlt_multitrack this = calloc( sizeof( struct mlt_multitrack_s ), 1 );
+
+       if ( this != NULL )
+       {
+               mlt_producer producer = &this->parent;
+               if ( mlt_producer_init( producer, this ) == 0 )
+               {
+                       producer->get_frame = producer_get_frame;
+               }
+               else
+               {
+                       free( this );
+                       this = NULL;
+               }
+       }
+       
+       return this;
+}
+
+/** Get the producer associated to this multitrack.
+*/
+
+mlt_producer mlt_multitrack_producer( mlt_multitrack this )
+{
+       return &this->parent;
+}
+
+/** Get the service associated this multitrack.
+*/
+
+mlt_service mlt_multitrack_service( mlt_multitrack this )
+{
+       return mlt_producer_service( mlt_multitrack_producer( this ) );
+}
+
+/** Get the properties associated this multitrack.
+*/
+
+mlt_properties mlt_multitrack_properties( mlt_multitrack this )
+{
+       return mlt_service_properties( mlt_multitrack_service( this ) );
+}
+
+/** Initialise timecode related information.
+*/
+
+static void mlt_multitrack_refresh( mlt_multitrack this )
+{
+       int i = 0;
+
+       // Obtain the properties of this multitrack
+       mlt_properties properties = mlt_multitrack_properties( this );
+
+       // We need to ensure that the multitrack reports the longest track as its length
+       mlt_timecode length = 0;
+
+       // We need to ensure that fps are the same on all services
+       double fps = 0;
+       
+       // Obtain stats on all connected services
+       for ( i = 0; i < this->count; i ++ )
+       {
+               // Get the producer from this index
+               mlt_producer producer = this->list[ i ];
+
+               // If it's allocated then, update our stats
+               if ( producer != NULL )
+               {
+                       // Determine the longest length
+                       length = mlt_producer_get_length( producer ) > length ? mlt_producer_get_length( producer ) : length;
+                       
+                       // Handle fps
+                       if ( fps == 0 )
+                       {
+                               // This is the first producer, so it controls the fps
+                               fps = mlt_producer_get_fps( producer );
+                       }
+                       else if ( fps != mlt_producer_get_fps( producer ) )
+                       {
+                               // Generate a warning for now - the following attempt to fix may fail
+                               fprintf( stderr, "Warning: fps mismatch on track %d\n", i );
+
+                               // It should be safe to impose fps on an image producer, but not necessarily safe for video
+                               mlt_properties_set_double( mlt_producer_properties( producer ), "fps", fps );
+                       }
+               }
+       }
+
+       // Update multitrack properties now - we'll not destroy the in point here
+       mlt_properties_set_timecode( properties, "length", length );
+       mlt_properties_set_timecode( properties, "out", length );
+       mlt_properties_set_timecode( properties, "playtime", length - mlt_properties_get_timecode( properties, "in" ) );
+}
+
+/** Connect a producer to a given track.
+*/
+
+int mlt_multitrack_connect( mlt_multitrack this, mlt_producer producer, int track )
+{
+       // Connect to the producer to ourselves at the specified track
+       int result = mlt_service_connect_producer( mlt_multitrack_service( this ), mlt_producer_service( producer ), track );
+
+       if ( result == 0 )
+       {
+               // Resize the producer list if need be
+               if ( track >= this->size )
+               {
+                       int i;
+                       this->list = realloc( this->list, ( track + 10 ) * sizeof( mlt_producer ) );
+                       for ( i = this->size; i < track + 10; i ++ )
+                               this->list[ i ] = NULL;
+                       this->size = track + 10;
+               }
+               
+               // Assign the track in our list here
+               this->list[ track ] = producer;
+               
+               // Increment the track count if need be
+               if ( track >= this->count )
+                       this->count = track + 1;
+                       
+               // Refresh our stats
+               mlt_multitrack_refresh( this );
+       }
+
+       return result;
+}
+
+/** Get frame method.
+
+       Special case here: The multitrack must be used in a conjunction with a downstream
+       tractor-type service, ie:
+
+       Producer1 \
+       Producer2 - multitrack - { filters/transitions } - tractor - consumer
+       Producer3 /
+
+       The get_frame of a tractor pulls frames from it's connected service on all tracks and 
+       will terminate as soon as it receives a test card with a last_track property. The 
+       important case here is that the mulitrack does not move to the next frame until all
+       tracks have been pulled. 
+
+       Reasoning: In order to seek on a network such as above, the multitrack needs to ensure
+       that all producers are positioned on the same frame. It uses the 'last track' logic
+       to determine when to move to the next frame.
+
+       Flaw: if a transition is configured to read from a b-track which happens to trigger
+       the last frame logic (ie: it's configured incorrectly), then things are going to go
+       out of sync.
+
+       See playlist logic too.
+*/
+
+static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index )
+{
+       // Get the mutiltrack object
+       mlt_multitrack this = parent->child;
+
+       // Check if we have a track for this index
+       if ( index < this->count && this->list[ index ] != NULL )
+       {
+               // Get the producer for this track
+               mlt_producer producer = this->list[ index ];
+
+               // Obtain the current timecode
+               uint64_t position = mlt_producer_frame( parent );
+
+               // Make sure we're at the same point
+               mlt_producer_seek_frame( producer, position );
+
+               // Get the frame from the producer
+               mlt_service_get_frame( mlt_producer_service( producer ), frame, 0 );
+       }
+       else
+       {
+               // Generate a test frame
+               *frame = mlt_frame_init( );
+
+               // Let tractor know if we've reached the end
+               mlt_properties_set_int( mlt_frame_properties( *frame ), "last_track", index >= this->count );
+
+               // Update timecode on the frame we're creating
+               mlt_frame_set_timecode( *frame, mlt_producer_position( parent ) );
+
+               // Move on to the next frame
+               if ( index >= this->count )
+                       mlt_producer_prepare_next( parent );
+       }
+
+       fprintf( stderr, "timestamp for %d = %f\n", index, ( float )mlt_frame_get_timecode( *frame ) );
+
+       return 0;
+}
+
+/** Close this instance.
+*/
+
+void mlt_multitrack_close( mlt_multitrack this )
+{
+       // Close the producer
+       mlt_producer_close( &this->parent );
+
+       // Free the list
+       free( this->list );
+
+       // Free the object
+       free( this );
+}
diff --git a/src/framework/mlt_multitrack.h b/src/framework/mlt_multitrack.h
new file mode 100644 (file)
index 0000000..9f85fc1
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * mlt_multitrack.h -- multitrack service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_MULITRACK_H_
+#define _MLT_MULITRACK_H_
+
+#include "mlt_producer.h"
+
+/** Public final methods
+*/
+
+extern mlt_multitrack mlt_multitrack_init( );
+extern mlt_producer mlt_multitrack_producer( mlt_multitrack this );
+extern mlt_service mlt_multitrack_service( mlt_multitrack this );
+extern int mlt_multitrack_connect( mlt_multitrack this, mlt_producer producer, int track );
+extern void mlt_multitrack_close( mlt_multitrack this );
+
+#endif
+
diff --git a/src/framework/mlt_playlist.c b/src/framework/mlt_playlist.c
new file mode 100644 (file)
index 0000000..ffcb3d5
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * mlt_playlist.c -- playlist service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "mlt_playlist.h"
+
+/** Private definition.
+*/
+
+struct mlt_playlist_s
+{
+       struct mlt_producer_s parent;
+       int count;
+       int track;
+};
+
+/** Constructor.
+
+       TODO: Override and implement all transport related method.
+       TODO: Override and implement a time code normalising service get_frame
+*/
+
+mlt_playlist mlt_playlist_init( )
+{
+       mlt_playlist this = calloc( sizeof( struct mlt_playlist_s ), 1 );
+       if ( this != NULL )
+       {
+               mlt_producer producer = &this->parent;
+               if ( mlt_producer_init( producer, this ) != 0 )
+               {
+                       free( this );
+                       this = NULL;
+               }
+       }
+       
+       return this;
+}
+
+/** Get the producer associated to this playlist.
+*/
+
+mlt_producer mlt_playlist_producer( mlt_playlist this )
+{
+       return &this->parent;
+}
+
+/** Get the service associated to this playlist.
+*/
+
+mlt_service mlt_playlist_service( mlt_playlist this )
+{
+       return mlt_producer_service( &this->parent );
+}
+
+/** Append a producer to the playlist.
+
+       TODO: Implement
+       TODO: Extract length information from the producer.
+*/
+
+int mlt_playlist_append( mlt_playlist this, mlt_producer producer )
+{
+       return 0;
+}
+
+/** Append a blank to the playlist of a given length.
+
+       TODO: Implement
+*/
+
+int mlt_playlist_blank( mlt_playlist this, mlt_timecode length )
+{
+       return 0;
+}
+
+/** Close the playlist.
+*/
+
+mlt_playlist_close( mlt_playlist this )
+{
+       mlt_producer_close( &this->parent );
+       free( this );
+}
diff --git a/src/framework/mlt_playlist.h b/src/framework/mlt_playlist.h
new file mode 100644 (file)
index 0000000..aa916c8
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * mlt_playlist.h -- playlist service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_PLAYLIST_H_
+#define _MLT_PLAYLIST_H_
+
+#include "mlt_producer.h"
+
+/** Public final methods
+*/
+
+extern mlt_playlist mlt_playlist_init( );
+extern mlt_producer mlt_playlist_producer( mlt_playlist this );
+extern mlt_service mlt_playlist_service( mlt_playlist this );
+extern int mlt_playlist_append( mlt_playlist this, mlt_producer producer );
+extern int mlt_playlist_pad( mlt_playlist this, mlt_timecode length );
+extern mlt_playlist_close( mlt_playlist this );
+
+#endif
+
diff --git a/src/framework/mlt_producer.c b/src/framework/mlt_producer.c
new file mode 100644 (file)
index 0000000..91e3989
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * mlt_producer.c -- abstraction for all producer services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "mlt_producer.h"
+#include "mlt_frame.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+/** Forward references.
+*/
+
+static int producer_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
+
+/** Constructor
+*/
+
+int mlt_producer_init( mlt_producer this, void *child )
+{
+       // Initialise the producer
+       memset( this, 0, sizeof( struct mlt_producer_s ) );
+       
+       // Associate with the child
+       this->child = child;
+
+       // Initialise the service
+       if ( mlt_service_init( &this->parent, this ) == 0 )
+       {
+               // The parent is the service
+               mlt_service parent = &this->parent;
+
+               // Get the properties of the parent
+               mlt_properties properties = mlt_service_properties( parent );
+
+               // Set the default properties
+               mlt_properties_set_timecode( properties, "position", 0.0 );
+               mlt_properties_set_double( properties, "frame", 1 );
+               mlt_properties_set_double( properties, "fps", 25.0 );
+               mlt_properties_set_double( properties, "speed", 1.0 );
+               mlt_properties_set_timecode( properties, "in", 0.0 );
+               mlt_properties_set_timecode( properties, "out", 36000.0 );
+               mlt_properties_set_timecode( properties, "playtime", 36000.0 );
+               mlt_properties_set_timecode( properties, "length", 36000.0 );
+
+               // Override service get_frame
+               parent->get_frame = producer_get_frame;
+       }
+
+       return 0;
+}
+
+/** Get the parent service object.
+*/
+
+mlt_service mlt_producer_service( mlt_producer this )
+{
+       return &this->parent;
+}
+
+/** Get the producer properties.
+*/
+
+mlt_properties mlt_producer_properties( mlt_producer this )
+{
+       return mlt_service_properties( &this->parent );
+}
+
+/** Seek to a specified time code.
+*/
+
+int mlt_producer_seek( mlt_producer this, mlt_timecode timecode )
+{
+       // Check bounds
+       if ( timecode < 0 )
+               timecode = 0;
+       if ( timecode > mlt_producer_get_playtime( this ) )
+               timecode = mlt_producer_get_playtime( this );
+
+       // Set the position
+       mlt_properties_set_timecode( mlt_producer_properties( this ), "position", timecode );
+
+       // Calculate the absolute frame
+       double frame = ( mlt_producer_get_in( this ) + timecode ) * mlt_producer_get_fps( this );
+       mlt_properties_set_double( mlt_producer_properties( this ), "frame", floor( frame + 0.5 ) );
+
+       return 0;
+}
+
+/** Seek to a specified absolute frame.
+*/
+
+int mlt_producer_seek_frame( mlt_producer this, uint64_t frame )
+{
+       // Calculate the time code
+       double timecode = ( frame / mlt_producer_get_fps( this ) ) - mlt_producer_get_in( this );
+
+       // If timecode is invalid, then seek on time
+       if ( timecode < 0 )
+       {
+               // Seek to the in point
+               mlt_producer_seek( this, 0 );
+       }
+       else if ( timecode > mlt_producer_get_playtime( this ) )
+       {
+               // Seek to the out point
+               mlt_producer_seek( this, mlt_producer_get_playtime( this ) );
+       }
+       else
+       {
+               // Set the position
+               mlt_properties_set_timecode( mlt_producer_properties( this ), "position", timecode );
+
+               // Set the absolute frame
+               mlt_properties_set_double( mlt_producer_properties( this ), "frame", frame );
+       }
+
+       return 0;
+}
+
+/** Get the current time code.
+*/
+
+mlt_timecode mlt_producer_position( mlt_producer this )
+{
+       return mlt_properties_get_timecode( mlt_producer_properties( this ), "position" );
+}
+
+/** Get the current frame.
+*/
+
+uint64_t mlt_producer_frame( mlt_producer this )
+{
+       return mlt_properties_get_double( mlt_producer_properties( this ), "frame" );
+}
+
+/** Set the playing speed.
+*/
+
+int mlt_producer_set_speed( mlt_producer this, double speed )
+{
+       return mlt_properties_set_double( mlt_producer_properties( this ), "speed", speed );
+}
+
+/** Get the playing speed.
+*/
+
+double mlt_producer_get_speed( mlt_producer this )
+{
+       return mlt_properties_get_double( mlt_producer_properties( this ), "speed" );
+}
+
+/** Get the frames per second.
+*/
+
+double mlt_producer_get_fps( mlt_producer this )
+{
+       return mlt_properties_get_double( mlt_producer_properties( this ), "fps" );
+}
+
+/** Set the in and out points.
+*/
+
+int mlt_producer_set_in_and_out( mlt_producer this, mlt_timecode in, mlt_timecode out )
+{
+       // Correct ins and outs if necessary
+       if ( in < 0 )
+               in = 0;
+       if ( in > mlt_producer_get_length( this ) )
+               in = mlt_producer_get_length( this );
+       if ( out < 0 )
+               out = 0;
+       if ( out > mlt_producer_get_length( this ) )
+               out = mlt_producer_get_length( this );
+
+       // Swap ins and outs if wrong
+       if ( out < in )
+       {
+               mlt_timecode t = in;
+               in = out;
+               out = t;
+       }
+
+       // Set the values
+       mlt_properties_set_timecode( mlt_producer_properties( this ), "in", in );
+       mlt_properties_set_timecode( mlt_producer_properties( this ), "out", out );
+       mlt_properties_set_timecode( mlt_producer_properties( this ), "playtime", out - in );
+
+       // Seek to the in point
+       mlt_producer_seek( this, 0 );
+
+       return 0;
+}
+
+/** Get the in point.
+*/
+
+mlt_timecode mlt_producer_get_in( mlt_producer this )
+{
+       return mlt_properties_get_timecode( mlt_producer_properties( this ), "in" );
+}
+
+/** Get the out point.
+*/
+
+mlt_timecode mlt_producer_get_out( mlt_producer this )
+{
+       return mlt_properties_get_timecode( mlt_producer_properties( this ), "out" );
+}
+
+/** Get the total play time.
+*/
+
+mlt_timecode mlt_producer_get_playtime( mlt_producer this )
+{
+       return mlt_properties_get_timecode( mlt_producer_properties( this ), "playtime" );
+}
+
+/** Get the total length of the producer.
+*/
+
+mlt_timecode mlt_producer_get_length( mlt_producer this )
+{
+       return mlt_properties_get_timecode( mlt_producer_properties( this ), "length" );
+}
+
+/** Prepare for next frame.
+*/
+
+void mlt_producer_prepare_next( mlt_producer this )
+{
+       mlt_producer_seek_frame( this, mlt_producer_frame( this ) + mlt_producer_get_speed( this ) );
+}
+
+/** Get a frame.
+*/
+
+static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
+{
+       int result = 1;
+       mlt_producer this = service->child;
+
+       // A properly instatiated producer will have a get_frame method...
+       if ( this->get_frame != NULL )
+       {
+               // Get the frame from the implementation
+               result = this->get_frame( this, frame, index );
+       }
+       else
+       {
+               // Generate a test frame
+               *frame = mlt_frame_init( );
+
+               // Set the timecode
+               result = mlt_frame_set_timecode( *frame, mlt_producer_position( this ) );
+
+               // Calculate the next timecode
+               mlt_producer_prepare_next( this );
+       }
+
+       return 0;
+}
+
+/** Close the producer.
+*/
+
+void mlt_producer_close( mlt_producer this )
+{
+       if ( this->close != NULL )
+               this->close( this );
+       else
+               mlt_service_close( &this->parent );
+}
diff --git a/src/framework/mlt_producer.h b/src/framework/mlt_producer.h
new file mode 100644 (file)
index 0000000..a59a82d
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * mlt_producer.h -- abstraction for all producer services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_PRODUCER_H_
+#define _MLT_PRODUCER_H_
+
+#include "mlt_service.h"
+
+/** The interface definition for all producers.
+*/
+
+struct mlt_producer_s
+{
+       // We're implementing service here
+       struct mlt_service_s parent;
+
+       // Public virtual methods
+       int ( *get_frame )( mlt_producer, mlt_frame_ptr, int );
+       void ( *close )( mlt_producer );
+
+       // Private data
+       void *private;
+       void *child;
+};
+
+/** Public final methods
+*/
+
+extern int mlt_producer_init( mlt_producer this, void *child );
+extern mlt_service mlt_producer_service( mlt_producer this );
+extern mlt_properties mlt_producer_properties( mlt_producer this );
+extern int mlt_producer_seek( mlt_producer this, mlt_timecode timecode );
+extern int mlt_producer_seek_frame( mlt_producer this, uint64_t frame );
+extern mlt_timecode mlt_producer_position( mlt_producer this );
+extern uint64_t mlt_producer_frame( mlt_producer this );
+extern int mlt_producer_set_speed( mlt_producer this, double speed );
+extern double mlt_producer_get_speed( mlt_producer this );
+extern double mlt_producer_get_fps( mlt_producer this );
+extern int mlt_producer_set_in_and_out( mlt_producer this, mlt_timecode in, mlt_timecode out );
+extern mlt_timecode mlt_producer_get_in( mlt_producer this );
+extern mlt_timecode mlt_producer_get_out( mlt_producer this );
+extern mlt_timecode mlt_producer_get_playtime( mlt_producer this );
+extern mlt_timecode mlt_producer_get_length( mlt_producer this );
+extern void mlt_producer_prepare_next( mlt_producer this );
+extern void mlt_producer_close( mlt_producer this );
+
+#endif
diff --git a/src/framework/mlt_properties.c b/src/framework/mlt_properties.c
new file mode 100644 (file)
index 0000000..233e8ac
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * mlt_properties.c -- base properties class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "mlt_properties.h"
+#include "mlt_property.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* ---------------- // Private Implementation // ---------------- */
+
+/** Private implementation of the property list.
+*/
+
+typedef struct
+{
+       char **name;
+       mlt_property *value;
+       int count;
+       int size;
+}
+property_list;
+
+/** Basic implementation.
+*/
+
+int mlt_properties_init( mlt_properties this, void *child )
+{
+       // NULL all methods
+       memset( this, 0, sizeof( struct mlt_properties_s ) );
+
+       // Assign the child of the object
+       this->child = child;
+
+       // Allocate the private structure
+       this->private = calloc( sizeof( property_list ), 1 );
+
+       return this->private == NULL;
+}
+
+/** Locate a property by name
+*/
+
+static mlt_property mlt_properties_find( mlt_properties this, char *name )
+{
+       mlt_property value = NULL;
+       property_list *list = this->private;
+       int i = 0;
+
+       // Locate the item 
+       for ( i = 0; value == NULL && i < list->count; i ++ )
+               if ( !strcmp( list->name[ i ], name ) )
+                       value = list->value[ i ];
+
+       return value;
+}
+
+/** Add a new property.
+*/
+
+static mlt_property mlt_properties_add( mlt_properties this, char *name )
+{
+       property_list *list = this->private;
+
+       // Check that we have space and resize if necessary
+       if ( list->count == list->size )
+       {
+               list->size += 10;
+               list->name = realloc( list->name, list->size * sizeof( char * ) );
+               list->value = realloc( list->value, list->size * sizeof( mlt_property ) );
+       }
+
+       // Assign name/value pair
+       list->name[ list->count ] = strdup( name );
+       list->value[ list->count ] = mlt_property_init( );
+
+       // Return and increment count accordingly
+       return list->value[ list->count ++ ];
+}
+
+/** Fetch a property by name - this includes add if not found.
+*/
+
+static mlt_property mlt_properties_fetch( mlt_properties this, char *name )
+{
+       // Try to find an existing property first
+       mlt_property property = mlt_properties_find( this, name );
+
+       // If it wasn't found, create one
+       if ( property == NULL )
+               property = mlt_properties_add( this, name );
+
+       // Return the property
+       return property;
+}
+
+/** Set the property.
+*/
+
+int mlt_properties_set( mlt_properties this, char *name, char *value )
+{
+       int error = 1;
+
+       // Fetch the property to work with
+       mlt_property property = mlt_properties_fetch( this, name );
+
+       // Set it if not NULL
+       if ( property != NULL )
+               error = mlt_property_set_string( property, value );
+
+       return error;
+}
+
+/** Get a string value by name.
+*/
+
+char *mlt_properties_get( mlt_properties this, char *name )
+{
+       mlt_property value = mlt_properties_find( this, name );
+       return value == NULL ? NULL : mlt_property_get_string( value );
+}
+
+/** Get a name by index.
+*/
+
+char *mlt_properties_get_name( mlt_properties this, int index )
+{
+       property_list *list = this->private;
+       if ( index >= 0 && index < list->count )
+               return list->name[ index ];
+       return NULL;
+}
+
+/** Get a string value by index.
+*/
+
+char *mlt_properties_get_value( mlt_properties this, int index )
+{
+       property_list *list = this->private;
+       if ( index >= 0 && index < list->count )
+               return mlt_property_get_string( list->value[ index ] );
+       return NULL;
+}
+
+/** Return the number of items in the list.
+*/
+
+int mlt_properties_count( mlt_properties this )
+{
+       property_list *list = this->private;
+       return list->count;
+}
+
+/** Set a value by parsing a name=value string
+*/
+
+int mlt_properties_parse( mlt_properties this, char *namevalue )
+{
+       char *name = strdup( namevalue );
+       char *value = strdup( namevalue );
+       int error = 0;
+
+       if ( strchr( name, '=' ) )
+       {
+               *( strchr( name, '=' ) ) = '\0';
+               strcpy( value, strchr( value, '=' ) + 1 );
+       }
+       else
+       {
+               strcpy( value, "" );
+       }
+
+       error = mlt_properties_set( this, name, value );
+
+       free( name );
+       free( value );
+
+       return error;
+}
+
+/** Get a value associated to the name.
+*/
+
+int mlt_properties_get_int( mlt_properties this, char *name )
+{
+       mlt_property value = mlt_properties_find( this, name );
+       return value == NULL ? 0 : mlt_property_get_int( value );
+}
+
+/** Set a value associated to the name.
+*/
+
+int mlt_properties_set_int( mlt_properties this, char *name, int value )
+{
+       int error = 1;
+
+       // Fetch the property to work with
+       mlt_property property = mlt_properties_fetch( this, name );
+
+       // Set it if not NULL
+       if ( property != NULL )
+               error = mlt_property_set_int( property, value );
+
+       return error;
+}
+
+/** Get a value associated to the name.
+*/
+
+double mlt_properties_get_double( mlt_properties this, char *name )
+{
+       mlt_property value = mlt_properties_find( this, name );
+       return value == NULL ? 0 : mlt_property_get_double( value );
+}
+
+/** Set a value associated to the name.
+*/
+
+int mlt_properties_set_double( mlt_properties this, char *name, double value )
+{
+       int error = 1;
+
+       // Fetch the property to work with
+       mlt_property property = mlt_properties_fetch( this, name );
+
+       // Set it if not NULL
+       if ( property != NULL )
+               error = mlt_property_set_double( property, value );
+
+       return error;
+}
+
+/** Get a value associated to the name.
+*/
+
+mlt_timecode mlt_properties_get_timecode( mlt_properties this, char *name )
+{
+       mlt_property value = mlt_properties_find( this, name );
+       return value == NULL ? 0 : mlt_property_get_timecode( value );
+}
+
+/** Set a value associated to the name.
+*/
+
+int mlt_properties_set_timecode( mlt_properties this, char *name, mlt_timecode value )
+{
+       int error = 1;
+
+       // Fetch the property to work with
+       mlt_property property = mlt_properties_fetch( this, name );
+
+       // Set it if not NULL
+       if ( property != NULL )
+               error = mlt_property_set_timecode( property, value );
+
+       return error;
+}
+
+/** Get a value associated to the name.
+*/
+
+void *mlt_properties_get_data( mlt_properties this, char *name, int *length )
+{
+       mlt_property value = mlt_properties_find( this, name );
+       return value == NULL ? NULL : mlt_property_get_data( value, length );
+}
+
+/** Set a value associated to the name.
+*/
+
+int mlt_properties_set_data( mlt_properties this, char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise )
+{
+       int error = 1;
+
+       // Fetch the property to work with
+       mlt_property property = mlt_properties_fetch( this, name );
+
+       // Set it if not NULL
+       if ( property != NULL )
+               error = mlt_property_set_data( property, value, length, destroy, serialise );
+
+       return error;
+}
+
+/** Close the list.
+*/
+
+void mlt_properties_close( mlt_properties this )
+{
+       property_list *list = this->private;
+       int index = 0;
+
+       // Clean up names and values
+       for ( index = 0; index < list->count; index ++ )
+       {
+               free( list->name[ index ] );
+               mlt_property_close( list->value[ index ] );
+       }
+
+       // Clear up the list
+       free( list->name );
+       free( list->value );
+       free( list );
+}
+
diff --git a/src/framework/mlt_properties.h b/src/framework/mlt_properties.h
new file mode 100644 (file)
index 0000000..b64753b
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * mlt_properties.h -- base properties class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_PROPERTIES_H_
+#define _MLT_PROPERTIES_H_
+
+#include "mlt_types.h"
+
+/** The properties base class defines the basic property propagation and
+       handling.
+*/
+
+struct mlt_properties_s
+{
+       void *child;
+       void *private;
+};
+
+/** Public interface.
+*/
+
+extern int mlt_properties_init( mlt_properties, void *child );
+extern int mlt_properties_set( mlt_properties this, char *name, char *value );
+extern int mlt_properties_parse( mlt_properties this, char *namevalue );
+extern char *mlt_properties_get( mlt_properties this, char *name );
+extern char *mlt_properties_get_name( mlt_properties this, int index );
+extern char *mlt_properties_get_value( mlt_properties this, int index );
+extern int mlt_properties_get_int( mlt_properties this, char *name );
+extern int mlt_properties_set_int( mlt_properties this, char *name, int value );
+extern double mlt_properties_get_double( mlt_properties this, char *name );
+extern int mlt_properties_set_double( mlt_properties this, char *name, double value );
+extern mlt_timecode mlt_properties_get_timecode( mlt_properties this, char *name );
+extern int mlt_properties_set_timecode( mlt_properties this, char *name, mlt_timecode value );
+extern int mlt_properties_set_data( mlt_properties this, char *name, void *value, int length, mlt_destructor, mlt_serialiser );
+extern void *mlt_properties_get_data( mlt_properties this, char *name, int *length );
+extern int mlt_properties_count( mlt_properties this );
+extern void mlt_properties_close( mlt_properties this );
+
+#endif
diff --git a/src/framework/mlt_property.c b/src/framework/mlt_property.c
new file mode 100644 (file)
index 0000000..021dbc1
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * mlt_property.c -- property class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "mlt_property.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** Construct and uninitialised property.
+*/
+
+mlt_property mlt_property_init( )
+{
+       return calloc( sizeof( struct mlt_property_s ), 1 );
+}
+
+/** Clear a property.
+*/
+
+void mlt_property_clear( mlt_property this )
+{
+       // Special case data handling
+       if ( this->types & mlt_prop_data && this->destructor != NULL )
+               this->destructor( this->data );
+
+       // Special case string handling
+       if ( this->types & mlt_prop_string )
+               free( this->prop_string );
+
+       // We can wipe it now.
+       memset( this, 0, sizeof( struct mlt_property_s ) );
+}
+
+/** Set an int on this property.
+*/
+
+int mlt_property_set_int( mlt_property this, int value )
+{
+       mlt_property_clear( this );
+       this->types = mlt_prop_int;
+       this->prop_int = value;
+       return 0;
+}
+
+/** Set a double on this property.
+*/
+
+int mlt_property_set_double( mlt_property this, double value )
+{
+       mlt_property_clear( this );
+       this->types = mlt_prop_double;
+       this->prop_double = value;
+       return 0;
+}
+
+/** Set a timecode on this property.
+*/
+
+int mlt_property_set_timecode( mlt_property this, mlt_timecode value )
+{
+       mlt_property_clear( this );
+       this->types = mlt_prop_timecode;
+       this->prop_timecode = value;
+       return 0;
+}
+
+/** Set a string on this property.
+*/
+
+int mlt_property_set_string( mlt_property this, char *value )
+{
+       mlt_property_clear( this );
+       this->types = mlt_prop_string;
+       if ( value != NULL )
+               this->prop_string = strdup( value );
+       return this->prop_string != NULL;
+}
+
+/** Set a data on this property.
+*/
+
+int mlt_property_set_data( mlt_property this, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser )
+{
+       mlt_property_clear( this );
+       this->types = mlt_prop_data;
+       this->data = value;
+       this->length = length;
+       this->destructor = destructor;
+       this->serialiser = serialiser;
+       return 0;
+}
+
+/** Get an int from this property.
+*/
+
+int mlt_property_get_int( mlt_property this )
+{
+       if ( this->types & mlt_prop_int )
+               return this->prop_int;
+       else if ( this->types & mlt_prop_double )
+               return ( int )this->prop_double;
+       else if ( this->types & mlt_prop_timecode )
+               return ( int )this->prop_timecode;
+       else if ( this->types & mlt_prop_string )
+               return atoi( this->prop_string );
+       return 0;
+}
+
+/** Get a double from this property.
+*/
+
+double mlt_property_get_double( mlt_property this )
+{
+       if ( this->types & mlt_prop_double )
+               return this->prop_double;
+       else if ( this->types & mlt_prop_int )
+               return ( double )this->prop_int;
+       else if ( this->types & mlt_prop_timecode )
+               return ( double )this->prop_timecode;
+       else if ( this->types & mlt_prop_string )
+               return atof( this->prop_string );
+       return 0;
+}
+
+/** Get a timecode from this property.
+*/
+
+mlt_timecode mlt_property_get_timecode( mlt_property this )
+{
+       if ( this->types & mlt_prop_timecode )
+               return this->prop_timecode;
+       else if ( this->types & mlt_prop_int )
+               return ( mlt_timecode )this->prop_int;
+       else if ( this->types & mlt_prop_double )
+               return ( mlt_timecode )this->prop_double;
+       else if ( this->types & mlt_prop_string )
+               return ( mlt_timecode )atof( this->prop_string );
+       return 0;
+}
+
+/** Get a string from this property.
+*/
+
+char *mlt_property_get_string( mlt_property this )
+{
+       // Construct a string if need be
+       if ( ! ( this->types & mlt_prop_string ) )
+       {
+               if ( this->types & mlt_prop_int )
+               {
+                       this->types |= mlt_prop_string;
+                       this->prop_string = malloc( 32 );
+                       sprintf( this->prop_string, "%d", this->prop_int );
+               }
+               else if ( this->types & mlt_prop_double )
+               {
+                       this->types |= mlt_prop_string;
+                       this->prop_string = malloc( 32 );
+                       sprintf( this->prop_string, "%e", this->prop_double );
+               }
+               else if ( this->types & mlt_prop_timecode )
+               {
+                       this->types |= mlt_prop_string;
+                       this->prop_string = malloc( 32 );
+                       sprintf( this->prop_string, "%e", this->prop_timecode );
+               }
+               else if ( this->types & mlt_prop_data && this->serialiser != NULL )
+               {
+                       this->types |= mlt_prop_string;
+                       this->prop_string = this->serialiser( this->data, this->length );
+               }
+       }
+
+       // Return the string (may be NULL)
+       return this->prop_string;
+}
+
+/** Get a data and associated length.
+*/
+
+void *mlt_property_get_data( mlt_property this, int *length )
+{
+       // Assign length if not NULL
+       if ( length != NULL )
+               *length = this->length;
+
+       // Return the data (note: there is no conversion here)
+       return this->data;
+}
+
+/** Close this property.
+*/
+
+void mlt_property_close( mlt_property this )
+{
+       mlt_property_clear( this );
+       free( this );
+}
+
+
diff --git a/src/framework/mlt_property.h b/src/framework/mlt_property.h
new file mode 100644 (file)
index 0000000..8fb209c
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * mlt_property.h -- property class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_PROPERTY_H_
+#define _MLT_PROPERTY_H_
+
+#include "mlt_types.h"
+
+/** Bit pattern for properties.
+*/
+
+typedef enum
+{
+       mlt_prop_none = 0,
+       mlt_prop_int = 1,
+       mlt_prop_string = 2,
+       mlt_prop_timecode = 4,
+       mlt_prop_double = 8,
+       mlt_prop_data = 16
+}
+mlt_property_type;
+
+/** Property structure.
+*/
+
+typedef struct mlt_property_s
+{
+       // Stores a bit pattern of types available for this property
+       mlt_property_type types;
+
+       // Atomic type handling
+       int prop_int;
+       mlt_timecode prop_timecode;
+       double prop_double;
+
+       // String handling
+       char *prop_string;
+
+       // Generic type handling
+       void *data;
+       int length;
+       mlt_destructor destructor;
+       mlt_serialiser serialiser;
+}
+*mlt_property;
+
+/** API
+*/
+
+extern mlt_property mlt_property_init( );
+extern void mlt_property_clear( mlt_property this );
+extern int mlt_property_set_int( mlt_property this, int value );
+extern int mlt_property_set_double( mlt_property this, double value );
+extern int mlt_property_set_timecode( mlt_property this, mlt_timecode value );
+extern int mlt_property_set_string( mlt_property this, char *value );
+extern int mlt_property_set_data( mlt_property this, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser );
+extern int mlt_property_get_int( mlt_property this );
+extern double mlt_property_get_double( mlt_property this );
+extern mlt_timecode mlt_property_get_timecode( mlt_property this );
+extern char *mlt_property_get_string( mlt_property this );
+extern void *mlt_property_get_data( mlt_property this, int *length );
+extern void mlt_property_close( mlt_property this );
+
+#endif
+
diff --git a/src/framework/mlt_repository.c b/src/framework/mlt_repository.c
new file mode 100644 (file)
index 0000000..9c41bf9
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * repository.c -- provides a map between service and shared objects
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "mlt_repository.h"
+#include <stdlib.h>
+
+struct mlt_repository_s
+{
+};
+
+mlt_repository mlt_repository_init( char *file, char *symbol )
+{
+       return NULL;
+}
+
+void *mlt_repository_fetch( mlt_repository this, char *service, void *input )
+{
+       return NULL;
+}
+
+void mlt_repository_close( mlt_repository this )
+{
+}
+
+
diff --git a/src/framework/mlt_repository.h b/src/framework/mlt_repository.h
new file mode 100644 (file)
index 0000000..afab1cc
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * repository.h -- provides a map between service and shared objects
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_REPOSITORY_H_
+#define _MLT_REPOSITORY_H_
+
+/** Repository structure forward reference.
+*/
+
+typedef struct mlt_repository_s *mlt_repository;
+
+/** Public functions.
+*/
+
+extern mlt_repository mlt_repository_init( char *file, char *symbol );
+extern void *mlt_repository_fetch( mlt_repository this, char *service, void *input );
+extern void mlt_repository_close( mlt_repository this );
+
+#endif
+
diff --git a/src/framework/mlt_service.c b/src/framework/mlt_service.c
new file mode 100644 (file)
index 0000000..8e626d4
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * mlt_service.c -- interface for all service classes
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "mlt_service.h"
+#include "mlt_frame.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** IMPORTANT NOTES
+
+       The base service implements a null frame producing service - as such,
+       it is functional without extension and will produce test cards frames 
+       and PAL sized audio frames.
+
+       PLEASE DO NOT CHANGE THIS BEHAVIOUR!!! OVERRIDE THE METHODS THAT 
+       CONTROL THIS IN EXTENDING CLASSES.
+*/
+
+/** Private service definition.
+*/
+
+typedef struct
+{
+       int size;
+       int count;
+       mlt_service *in;
+       mlt_service out;
+}
+mlt_service_base;
+
+/** Friends?
+*/
+
+static void mlt_service_disconnect( mlt_service this );
+static void mlt_service_connect( mlt_service this, mlt_service that );
+static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
+
+/** Constructor
+*/
+
+int mlt_service_init( mlt_service this, void *child )
+{
+       // Initialise everything to NULL
+       memset( this, 0, sizeof( struct mlt_service_s ) );
+
+       // Assign the child
+       this->child = child;
+
+       // Generate private space
+       this->private = calloc( sizeof( mlt_service_base ), 1 );
+
+       // Associate the methods
+       this->get_frame = service_get_frame;
+       
+       // Initialise the properties
+       return mlt_properties_init( &this->parent, this );
+}
+
+/** Return the properties object.
+*/
+
+mlt_properties mlt_service_properties( mlt_service this )
+{
+       return &this->parent;
+}
+
+/** Connect a producer service.
+       Returns: > 0 warning, == 0 success, < 0 serious error
+                        1 = this service does not accept input
+                        2 = the producer is invalid
+                        3 = the producer is already registered with this consumer
+*/
+
+int mlt_service_connect_producer( mlt_service this, mlt_service producer, int index )
+{
+       int i = 0;
+
+       // Get the service base
+       mlt_service_base *base = this->private;
+
+       // Does this service accept input?
+       if ( mlt_service_accepts_input( this ) == 0 )
+               return 1;
+
+       // Does the producer service accept output connections?
+       if ( mlt_service_accepts_output( producer ) == 0 )
+               return 2;
+
+       // Check if the producer is already registered with this service
+       for ( i = 0; i < base->count; i ++ )
+               if ( base->in[ i ] == producer )
+                       return 3;
+
+       // Allocate space
+       if ( index >= base->size )
+       {
+               int new_size = base->size + index + 10;
+               base->in = realloc( base->in, new_size * sizeof( mlt_service ) );
+               if ( base->in != NULL )
+               {
+                       for ( i = base->size; i < new_size; i ++ )
+                               base->in[ i ] = NULL;
+                       base->size = new_size;
+               }
+       }
+
+       // If we have space, assign the input
+       if ( base->in != NULL && index >= 0 && index < base->size )
+       {
+               // Now we disconnect the producer service from its consumer
+               mlt_service_disconnect( producer );
+               
+               // Add the service to index specified
+               base->in[ index ] = producer;
+               
+               // Determine the number of active tracks
+               if ( index >= base->count )
+                       base->count = index + 1;
+
+               // Now we connect the producer to its connected consumer
+               mlt_service_connect( producer, this );
+
+               // Inform caller that all went well
+               return 0;
+       }
+       else
+       {
+               return -1;
+       }
+}
+
+/** Disconnect this service from its consumer.
+*/
+
+void mlt_service_disconnect( mlt_service this )
+{
+       // Get the service base
+       mlt_service_base *base = this->private;
+
+       // There's a bit more required here...
+       base->out = NULL;
+}
+
+/** Associate this service to the its consumer.
+*/
+
+void mlt_service_connect( mlt_service this, mlt_service that )
+{
+       // Get the service base
+       mlt_service_base *base = this->private;
+
+       // There's a bit more required here...
+       base->out = that;
+}
+
+/** Get the service state.
+*/
+
+mlt_service_state mlt_service_get_state( mlt_service this )
+{
+       mlt_service_state state = mlt_state_unknown;
+       if ( mlt_service_has_input( this ) )
+               state |= mlt_state_providing;
+       if ( mlt_service_has_output( this ) )
+               state |= mlt_state_connected;
+       if ( state != ( mlt_state_providing | mlt_state_connected ) )
+               state |= mlt_state_dormant;
+       return state;
+}
+
+/** Get the maximum number of inputs accepted.
+       Returns: -1 for many, 0 for none or n for fixed.
+*/
+
+int mlt_service_accepts_input( mlt_service this )
+{
+       if ( this->accepts_input == NULL )
+               return -1;
+       else
+               return this->accepts_input( this );
+}
+
+/** Get the maximum number of outputs accepted.
+*/
+
+int mlt_service_accepts_output( mlt_service this )
+{
+       if ( this->accepts_output == NULL )
+               return 1;
+       else
+               return this->accepts_output( this );
+}
+
+/** Determines if this service has input
+*/
+
+int mlt_service_has_input( mlt_service this )
+{
+       if ( this->has_input == NULL )
+               return 1;
+       else
+               return this->has_input( this );
+}
+
+/** Determine if this service has output
+*/
+
+int mlt_service_has_output( mlt_service this )
+{
+       mlt_service_base *base = this->private;
+       if ( this->has_output == NULL )
+               return base->out != NULL;
+       else
+               return this->has_output( this );
+}
+
+/** Check if the service is active.
+*/
+
+int mlt_service_is_active( mlt_service this )
+{
+       return !( mlt_service_get_state( this ) & mlt_state_dormant );
+}
+
+/** Obtain a frame to pass on.
+*/
+
+static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
+{
+       mlt_service_base *base = this->private;
+       if ( index < base->count )
+       {
+               mlt_service producer = base->in[ index ];
+               if ( producer != NULL )
+                       return mlt_service_get_frame( producer, frame, index );
+       }
+       *frame = mlt_frame_init( );
+       return 0;
+}
+
+int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
+{
+       return this->get_frame( this, frame, index );
+}
+
+/** Close the service.
+*/
+
+void mlt_service_close( mlt_service this )
+{
+       mlt_service_base *base = this->private;
+       free( base->in );
+       free( base );
+       mlt_properties_close( &this->parent );
+}
+
diff --git a/src/framework/mlt_service.h b/src/framework/mlt_service.h
new file mode 100644 (file)
index 0000000..88b91b5
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * mlt_service.h -- interface for all service classes
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_SERVICE_H_
+#define _MLT_SERVICE_H_
+
+#include "mlt_properties.h"
+
+/** State of a service.
+
+    Note that a service may be dormant even though it's fully connected,
+       providing or consuming.
+*/
+
+typedef enum
+{
+       mlt_state_unknown   = 0,
+       mlt_state_dormant   = 1,
+       mlt_state_connected = 2,
+       mlt_state_providing = 4,
+       mlt_state_consuming = 8
+}
+mlt_service_state;
+
+/** The interface definition for all services.
+*/
+
+struct mlt_service_s
+{
+       // We're extending properties here
+       struct mlt_properties_s parent;
+
+       // Protected virtual
+       int ( *accepts_input )( mlt_service this );
+       int ( *accepts_output )( mlt_service this );
+       int ( *has_input )( mlt_service this );
+       int ( *has_output )( mlt_service this );
+       int ( *get_frame )( mlt_service this, mlt_frame_ptr frame, int index );
+
+       // Private data
+       void *private;
+       void *child;
+};
+
+/** The public API.
+*/
+
+extern int mlt_service_init( mlt_service this, void *child );
+extern mlt_properties mlt_service_properties( mlt_service this );
+extern int mlt_service_connect_producer( mlt_service this, mlt_service producer, int index );
+extern mlt_service_state mlt_service_get_state( mlt_service this );
+extern void mlt_service_close( mlt_service this );
+
+extern int mlt_service_accepts_input( mlt_service this );
+extern int mlt_service_accepts_output( mlt_service this );
+extern int mlt_service_has_input( mlt_service this );
+extern int mlt_service_has_output( mlt_service this );
+extern int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
+extern int mlt_service_is_active( mlt_service this );
+
+#endif
+
diff --git a/src/framework/mlt_tractor.c b/src/framework/mlt_tractor.c
new file mode 100644 (file)
index 0000000..f4b77c4
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * mlt_tractor.c -- tractor service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "mlt_tractor.h"
+#include "mlt_frame.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/** Private structure.
+*/
+
+struct mlt_tractor_s
+{
+       struct mlt_service_s parent;
+       mlt_service producer;
+};
+
+/** Forward references to static methods.
+*/
+
+static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int track );
+
+/** Constructor for the tractor.
+
+       TODO: thread this service...
+*/
+
+mlt_tractor mlt_tractor_init( )
+{
+       mlt_tractor this = calloc( sizeof( struct mlt_tractor_s ), 1 );
+       if ( this != NULL )
+       {
+               mlt_service service = &this->parent;
+               if ( mlt_service_init( service, this ) == 0 )
+               {
+                       service->get_frame = service_get_frame;
+               }
+               else
+               {
+                       free( this );
+                       this = NULL;
+               }
+       }
+       return this;
+}
+
+/** Get the service object associated to the tractor.
+*/
+
+mlt_service mlt_tractor_service( mlt_tractor this )
+{
+       return &this->parent;
+}
+
+/** Connect the tractor.
+*/
+
+int mlt_tractor_connect( mlt_tractor this, mlt_service producer )
+{
+       int ret = mlt_service_connect_producer( &this->parent, producer, 0 );
+
+       if ( ret == 0 )
+       {
+               // This is the producer we're going to connect to
+               this->producer = producer;
+       }
+
+       return ret;
+}
+
+/** Get the next frame.
+
+       TODO: This should be reading a pump being populated by the thread...
+*/
+
+static int service_get_frame( mlt_service parent, mlt_frame_ptr frame, int track )
+{
+       mlt_tractor this = parent->child;
+
+       // We only respond to the first track requests
+       if ( track == 0 && this->producer != NULL )
+       {
+               int i = 0;
+               int looking = 1;
+               int done = 0;
+               mlt_frame temp;
+
+               // Loop through each of the tracks we're harvesting
+               for ( i = 0; !done; i ++ )
+               {
+                       // Get a frame from the producer
+                       mlt_service_get_frame( this->producer, &temp, i );
+
+                       // Check for last track
+                       done = mlt_properties_get_int( mlt_frame_properties( temp ), "last_track" );
+
+                       // Handle the frame
+                       if ( done && looking )
+                       {
+                               // Use this as output if we don't have one already
+                               *frame = temp;
+                       }
+                       else if ( !mlt_frame_is_test_card( temp ) && looking )
+                       {
+                               // This is the one we want and we can stop looking
+                               *frame = temp;
+                               looking = 0;
+                       }
+                       else
+                       {
+                               // We discard all other frames
+                               mlt_frame_close( temp );
+                       }
+               }
+
+               // Indicate our found status
+               return 0;
+       }
+       else
+       {
+               // Generate a test card
+               *frame = mlt_frame_init( );
+               return 0;
+       }
+}
+
+/** Close the tractor.
+*/
+
+void mlt_tractor_close( mlt_tractor this )
+{
+       mlt_service_close( &this->parent );
+       free( this );
+}
+
diff --git a/src/framework/mlt_tractor.h b/src/framework/mlt_tractor.h
new file mode 100644 (file)
index 0000000..28a6071
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * mlt_tractor.h -- tractor service class
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_TRACTOR_H_
+#define _MLT_TRACTOR_H_
+
+#include "mlt_producer.h"
+
+extern mlt_tractor mlt_tractor_init( );
+extern mlt_service mlt_tractor_service( mlt_tractor this );
+extern int mlt_tractor_connect( mlt_tractor this, mlt_service service );
+extern void mlt_tractor_close( mlt_tractor this );
+
+#endif
diff --git a/src/framework/mlt_transition.c b/src/framework/mlt_transition.c
new file mode 100644 (file)
index 0000000..dd4f2f6
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * mlt_transition.c -- abstraction for all transition services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "mlt_transition.h"
+#include "mlt_frame.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** Forward references.
+*/
+
+static int transition_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
+
+/** Constructor.
+*/
+
+int mlt_transition_init( mlt_transition this, void *child )
+{
+       mlt_service service = &this->parent;
+       memset( this, 0, sizeof( struct mlt_transition_s ) );
+       this->child = child;
+       if ( mlt_service_init( service, this ) == 0 )
+       {
+               service->get_frame = transition_get_frame;
+               return 0;
+       }
+       return 1;
+}
+
+/** Get the service associated to the transition.
+*/
+
+mlt_service mlt_transition_service( mlt_transition this )
+{
+       return &this->parent;
+}
+
+/** Connect this transition with a producers a and b tracks.
+*/
+
+int mlt_transition_connect( mlt_transition this, mlt_service producer, int a_track, int b_track )
+{
+       int ret = mlt_service_connect_producer( &this->parent, producer, a_track );
+       if ( ret == 0 )
+       {
+               this->producer = producer;
+               this->a_track = a_track;
+               this->b_track = b_track;
+               this->in = 0;
+               this->out = 0;
+       }
+       return ret;
+}
+
+/** Set the in and out points.
+*/
+
+void mlt_transition_set_in_and_out( mlt_transition this, mlt_timecode in, mlt_timecode out )
+{
+       this->in = in;
+       this->out = out;
+}
+
+/** Get the index of the a track.
+*/
+
+int mlt_transition_get_a_track( mlt_transition this )
+{
+       return this->a_track;
+}
+
+/** Get the index of the b track.
+*/
+
+int mlt_transition_get_b_track( mlt_transition this )
+{
+       return this->b_track;
+}
+
+/** Get the in point.
+*/
+
+mlt_timecode mlt_transition_get_in( mlt_transition this )
+{
+       return this->in;
+}
+
+/** Get the out point.
+*/
+
+mlt_timecode mlt_transition_get_out( mlt_transition this )
+{
+       return this->out;
+}
+
+/** Process the frame.
+*/
+
+static mlt_frame transition_process( mlt_transition this, mlt_frame a_frame, mlt_frame b_frame )
+{
+       if ( this->process == NULL )
+       {
+               if ( !mlt_frame_is_test_card( a_frame ) )
+               {
+                       mlt_frame_close( b_frame );
+                       return a_frame;
+               }
+               else
+               {
+                       mlt_frame_close( a_frame );
+                       return b_frame;
+               }
+       }
+       else
+       {
+               return this->process( this, a_frame, b_frame );
+       }
+}
+
+/** Get a frame from this filter.
+
+       The logic is complex here. A transition is applied to frames on the a and b tracks
+       specified in the connect method above. Since all frames are obtained via this 
+       method for all tracks, we have to take special care that we only obtain the a and
+       b frames once - we do this on the first call to get a frame from either a or b.
+       
+       After that, we have 3 cases to resolve:
+       
+       1)      if the track is the a_track and we're in the time zone, then we need to call the
+               process method to do the effect on the frame (we assign NULL to the a_frame and
+               b_frames here) otherwise, we pass on the a_frame unmolested;
+       2)      if the track is the b_track and we're the in the time zone OR the b_frame is NULL,
+               then we generate a test card frame, otherwise we pass on the b frame unmolested;
+       3)      For all other tracks, we get the frames on demand.
+*/
+
+static int transition_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
+{
+       mlt_transition this = service->child;
+
+       // Fetch a and b frames together...
+       if ( ( index == this->a_track || index == this->b_track ) &&
+                ( this->a_frame == NULL && this->b_frame == NULL ) )
+       {
+               mlt_service_get_frame( this->producer, &this->a_frame, this->a_track );
+               mlt_service_get_frame( this->producer, &this->b_frame, this->b_track );
+       }
+       
+       // Special case track processing
+       if ( index == this->a_track )
+       {
+               // Determine if we're in the right time zone
+               mlt_timecode timecode = mlt_frame_get_timecode( this->a_frame );
+               if ( timecode >= this->in && timecode < this->out )
+               {
+                       // Process the transition
+                       *frame = transition_process( this, this->a_frame, this->b_frame );
+                       
+                       // Important - NULL both frames now so that we know they're done...
+                       this->a_frame = NULL;
+                       this->b_frame = NULL;
+               }
+               else
+               {
+                       // Pass on the 'a frame' and remember that we've done it
+                       *frame = this->a_frame;
+                       this->a_frame = NULL;
+               }                       
+               return 0;
+       }
+       if ( index == this->b_track )
+       {
+               if ( this->b_frame == NULL )
+               {
+                       // We're *probably* in the zone and the a frame has been requested
+                       *frame = mlt_frame_init( );
+               }
+               else
+               {
+                       mlt_timecode timecode = mlt_frame_get_timecode( this->b_frame );
+                       if ( timecode >= this->in && timecode < this->out )
+                       {
+                               // We're in the zone, but the 'a frame' has not been requested yet
+                               *frame = mlt_frame_init( );
+                       }
+                       else
+                       {
+                               // We're out of the zone, pass on b and remember that we've done it
+                               *frame = this->b_frame;
+                               this->b_frame = NULL;
+                       }
+               }
+               return 0;
+       }
+       else
+       {
+               // Pass through
+               return mlt_service_get_frame( this->producer, frame, index );
+       }
+}
+
+/** Close the transition.
+*/
+
+void mlt_transitition_close( mlt_transition this )
+{
+       if ( this->close != NULL )
+               this->close( this );
+       else
+               mlt_service_close( &this->parent );
+}
diff --git a/src/framework/mlt_transition.h b/src/framework/mlt_transition.h
new file mode 100644 (file)
index 0000000..397483f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * mlt_transition.h -- abstraction for all transition services
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_TRANSITION_H_
+#define _MLT_TRANSITION_H_
+
+#include "mlt_service.h"
+
+/** The interface definition for all transitions.
+*/
+
+struct mlt_transition_s
+{
+       // We're implementing service here
+       struct mlt_service_s parent;
+
+       // public virtual
+       void ( *close )( mlt_transition );
+
+       // protected transition method
+       mlt_frame ( *process )( mlt_transition, mlt_frame, mlt_frame );
+
+       // Protected
+       void *child;
+       
+       // track and in/out points
+       mlt_service producer;
+       int a_track;
+       int b_track;
+       mlt_timecode in;
+       mlt_timecode out;
+       
+       // Private
+       mlt_frame a_frame;
+       mlt_frame b_frame;
+};
+
+/** Public final methods
+*/
+
+extern int mlt_transition_init( mlt_transition this, void *child );
+extern mlt_service mlt_transition_service( mlt_transition this );
+extern int mlt_transition_connect( mlt_transition this, mlt_service producer, int a_track, int b_track );
+extern void mlt_transition_set_in_and_out( mlt_transition this, mlt_timecode in, mlt_timecode out );
+extern int mlt_transition_get_a_track( mlt_transition this );
+extern int mlt_transition_get_b_track( mlt_transition this );
+extern mlt_timecode mlt_transition_get_in( mlt_transition this );
+extern mlt_timecode mlt_transition_get_out( mlt_transition this );
+extern void mlt_transitition_close( mlt_transition this );
+
+#endif
diff --git a/src/framework/mlt_types.h b/src/framework/mlt_types.h
new file mode 100644 (file)
index 0000000..aa97463
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * mlt_types.h -- provides forward definitions of all public types
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MLT_TYPES_H_
+#define _MLT_TYPES_H_
+
+#include <stdint.h>
+
+typedef double mlt_timecode;
+typedef struct mlt_frame_s *mlt_frame, **mlt_frame_ptr;
+typedef struct mlt_properties_s *mlt_properties;
+typedef struct mlt_service_s *mlt_service;
+typedef struct mlt_producer_s *mlt_producer;
+typedef struct mlt_manager_s *mlt_manager;
+typedef struct mlt_playlist_s *mlt_playlist;
+typedef struct mlt_multitrack_s *mlt_multitrack;
+typedef struct mlt_filter_s *mlt_filter;
+typedef struct mlt_transition_s *mlt_transition;
+typedef struct mlt_consumer_s *mlt_consumer;
+typedef struct mlt_tractor_s *mlt_tractor;
+
+typedef void ( *mlt_destructor )( void * );
+typedef char *( *mlt_serialiser )( void *, int length );
+
+
+#endif
diff --git a/src/miracle/configure b/src/miracle/configure
new file mode 100755 (executable)
index 0000000..1a24852
--- /dev/null
@@ -0,0 +1 @@
+#!/bin/sh
diff --git a/src/miracle/miracle.c b/src/miracle/miracle.c
new file mode 100644 (file)
index 0000000..47a645a
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * dv1394d.c -- A DV over IEEE 1394 TCP Server
+ *
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Authors:
+ *     Dan Dennedy <dan@dennedy.org>
+ *     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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+
+/* Application header files */
+#include "dvserver.h"
+#include "log.h"
+
+/** Our dv server.
+*/
+
+static dv_server server = NULL;
+
+/** atexit shutdown handler for the server.
+*/
+
+static void main_cleanup( )
+{
+       dv_server_shutdown( server );
+}
+
+/** Report usage and exit.
+*/
+
+void usage( char *app )
+{
+       fprintf( stderr, "Usage: %s [-test] [-port NNNN]\n", app );
+       exit( 0 );
+}
+
+/** The main function.
+*/
+
+int main( int argc, char **argv )
+{
+       int error = 0;
+       int index = 0;
+       int background = 1;
+       struct timespec tm = { 5, 0 };
+
+       server = dv_server_init( argv[ 0 ] );
+
+       for ( index = 1; index < argc; index ++ )
+       {
+               if ( !strcmp( argv[ index ], "-port" ) )
+                       dv_server_set_port( server, atoi( argv[ ++ index ] ) );
+               else if ( !strcmp( argv[ index ], "-proxy" ) )
+                       dv_server_set_proxy( server, argv[ ++ index ] );
+               else if ( !strcmp( argv[ index ], "-test" ) )
+                       background = 0;
+               else
+                       usage( argv[ 0 ] );
+       }
+
+       /* Optionally detatch ourselves from the controlling tty */
+
+       if ( background )
+       {
+               if ( fork() )
+                       return 0;
+               setsid();
+               dv1394d_log_init( log_syslog, LOG_INFO );
+       }
+       else
+       {
+               dv1394d_log_init( log_stderr, LOG_INFO );
+       }
+
+       atexit( main_cleanup );
+
+       /* Execute the server */
+       error = dv_server_execute( server );
+
+       /* We need to wait until we're exited.. */
+       while ( !server->shutdown )
+               nanosleep( &tm, NULL );
+
+       return error;
+}
diff --git a/src/miracle/miracle_commands.c b/src/miracle/miracle_commands.c
new file mode 100644 (file)
index 0000000..8a492d1
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * global_commands.c
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <pthread.h>
+
+#include "dvunit.h"
+#include "global_commands.h"
+#include "raw1394util.h"
+#include <libavc1394/rom1394.h>
+#include "log.h"
+
+static dv_unit g_units[MAX_UNITS];
+
+
+/** Return the dv_unit given a numeric index.
+*/
+
+dv_unit dv1394d_get_unit( int n )
+{
+       if (n < MAX_UNITS)
+               return g_units[n];
+       else
+               return NULL;
+}
+
+/** Destroy the dv_unit given its numeric index.
+*/
+
+void dv1394d_delete_unit( int n )
+{
+       if (n < MAX_UNITS)
+       {
+               dv_unit unit = dv1394d_get_unit(n);
+               if (unit != NULL)
+               {
+                       dv_unit_close( unit );
+                       g_units[ n ] = NULL;
+                       dv1394d_log( LOG_NOTICE, "Deleted unit U%d.", n ); 
+               }
+       }
+}
+
+/** Destroy all allocated units on the server.
+*/
+
+void dv1394d_delete_all_units( void )
+{
+       int i;
+       for (i = 0; i < MAX_UNITS; i++)
+               if ( dv1394d_get_unit(i) != NULL )
+               {
+                       dv_unit_close( dv1394d_get_unit(i) );
+                       dv1394d_log( LOG_NOTICE, "Deleted unit U%d.", i ); 
+               }
+}
+
+/** Add a DV virtual vtr to the server.
+*/
+response_codes dv1394d_add_unit( command_argument cmd_arg )
+{
+       int i;
+       int channel = -1;
+       char *guid_str = (char*) cmd_arg->argument;
+       octlet_t guid;
+       uint32_t guid_hi;
+       uint32_t guid_lo;
+       
+       sscanf( guid_str, "%08x%08x", &guid_hi, &guid_lo );
+       guid = (octlet_t)guid_hi << 32 | (octlet_t) guid_lo;
+
+       if ( dv_tokeniser_count( cmd_arg->tokeniser ) == 3 )
+               channel = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 2 ) );
+
+       /* make sure unit does not already exit */
+       for (i = 0; i < MAX_UNITS; i++)
+       {
+               if (g_units[i] != NULL)
+                       if ( dv_unit_get_guid( g_units[i] ) == guid )
+                       {
+                               dv_response_printf( cmd_arg->response, 1024, "a unit already exists for that node\n\n" );
+                               return RESPONSE_ERROR;
+                       }
+       }
+       
+       for (i = 0; i < MAX_UNITS; i++)
+       {
+               if (g_units[i] == NULL)
+               {
+               
+                       g_units[ i ] = dv_unit_init( guid, channel );
+                       if ( g_units[ i ] == NULL )
+                       {
+                               dv_response_printf( cmd_arg->response, 1024, "failed to allocate unit\n" );
+                               return RESPONSE_ERROR;
+                       }
+                       g_units[ i ]->unit = i;
+                       dv_unit_set_notifier( g_units[ i ], dv_parser_get_notifier( cmd_arg->parser ), cmd_arg->root_dir );
+
+                       dv1394d_log( LOG_NOTICE, "added unit %d to send to node %d over channel %d", 
+                               i, dv_unit_get_nodeid( g_units[i] ), dv_unit_get_channel( g_units[i] ) );
+                       dv_response_printf( cmd_arg->response, 10, "U%1d\n\n", i );
+                       return RESPONSE_SUCCESS_N;
+               }
+       }
+       
+       dv_response_printf( cmd_arg->response, 1024, "no more units can be created\n\n" );
+
+       return RESPONSE_ERROR;
+}
+
+
+/** List all AV/C nodes on the bus.
+*/
+response_codes dv1394d_list_nodes( command_argument cmd_arg )
+{
+       response_codes error = RESPONSE_SUCCESS_N;
+       raw1394handle_t handle;
+       int i, j;
+       char line[1024];
+       octlet_t guid;
+       rom1394_directory dir;
+
+       for ( j = 0; j < raw1394_get_num_ports(); j++ )
+       {
+               handle = raw1394_open(j);
+               for ( i = 0; i < raw1394_get_nodecount(handle); ++i )
+               {
+                       rom1394_get_directory( handle, i, &dir);
+                       if ( (rom1394_get_node_type(&dir) == ROM1394_NODE_TYPE_AVC) )
+                       {
+                               guid = rom1394_get_guid(handle, i);
+                               if (dir.label != NULL)
+                               {
+                                       snprintf( line, 1023, "%02d %08x%08x \"%s\"\n", i, 
+                                               (quadlet_t) (guid>>32), (quadlet_t) (guid & 0xffffffff), dir.label );
+                               } else {
+                                       snprintf( line, 1023, "%02d %08x%08x \"Unlabeled Node %d\"\n", i, 
+                                               (quadlet_t) (guid>>32), (quadlet_t) (guid & 0xffffffff), i );
+                               }
+                               dv_response_write( cmd_arg->response, line, strlen(line) );
+                               rom1394_free_directory( &dir);
+                       }
+               }
+               raw1394_close( handle );
+       }
+       dv_response_write( cmd_arg->response, "\n", 1 );
+       return error;
+}
+
+
+/** List units already added to server.
+*/
+response_codes dv1394d_list_units( command_argument cmd_arg )
+{
+       response_codes error = RESPONSE_SUCCESS_N;
+       char line[1024];
+       int i;
+       
+       for (i = 0; i < MAX_UNITS; i++)
+       {
+               if (dv1394d_get_unit(i) != NULL)
+               {
+                       snprintf( line, 1023, "U%d %02d %08x%08x %d\n", i, dv_unit_get_nodeid(g_units[i]),
+                       (quadlet_t) (dv_unit_get_guid(g_units[i]) >> 32), 
+                       (quadlet_t) (dv_unit_get_guid(g_units[i]) & 0xffffffff),
+                       !dv_unit_is_offline( g_units[i] ) );
+                       dv_response_write( cmd_arg->response, line, strlen(line) );
+               }
+       }
+       dv_response_write( cmd_arg->response, "\n", 1 );
+
+       return error;
+}
+
+static int
+filter_files( const struct dirent *de )
+{
+       if ( de->d_name[ 0 ] != '.' )
+               return 1;
+       else
+               return 0;
+}
+
+/** List clips in a directory.
+*/
+response_codes dv1394d_list_clips( command_argument cmd_arg )
+{
+       response_codes error = RESPONSE_BAD_FILE;
+       const char *dir_name = (const char*) cmd_arg->argument;
+       DIR *dir;
+       char fullname[1024];
+       struct dirent **de = NULL;
+       int i, n;
+       
+       snprintf( fullname, 1023, "%s%s", cmd_arg->root_dir, dir_name );
+       dir = opendir( fullname );
+       if (dir != NULL)
+       {
+               struct stat info;
+               error = RESPONSE_SUCCESS_N;
+               n = scandir( fullname, &de, filter_files, alphasort );
+               for (i = 0; i < n; i++ )
+               {
+                       snprintf( fullname, 1023, "%s%s/%s", cmd_arg->root_dir, dir_name, de[i]->d_name );
+                       if ( stat( fullname, &info ) == 0 && S_ISDIR( info.st_mode ) )
+                               dv_response_printf( cmd_arg->response, 1024, "\"%s/\"\n", de[i]->d_name );
+               }
+               for (i = 0; i < n; i++ )
+               {
+                       snprintf( fullname, 1023, "%s%s/%s", cmd_arg->root_dir, dir_name, de[i]->d_name );
+                       if ( lstat( fullname, &info ) == 0 && 
+                                ( S_ISREG( info.st_mode ) || ( strstr( fullname, ".clip" ) && info.st_mode | S_IXUSR ) ) )
+                               dv_response_printf( cmd_arg->response, 1024, "\"%s\" %llu\n", de[i]->d_name, (unsigned long long) info.st_size );
+                       free( de[ i ] );
+               }
+               free( de );
+               closedir( dir );
+               dv_response_write( cmd_arg->response, "\n", 1 );
+       }
+
+       return error;
+}
+
+/** Set a server configuration property.
+*/
+
+response_codes dv1394d_set_global_property( command_argument cmd_arg )
+{
+       char *key = (char*) cmd_arg->argument;
+       char *value = NULL;
+
+       value = strchr( key, '=' );
+       if (value == NULL)
+               return RESPONSE_OUT_OF_RANGE;
+       *value = 0;
+       value++;
+       dv1394d_log( LOG_DEBUG, "SET %s = %s", key, value );
+
+       if ( strncasecmp( key, "root", 1024) == 0 )
+       {
+               int len = strlen(value);
+               int i;
+               
+               /* stop all units and unload clips */
+               for (i = 0; i < MAX_UNITS; i++)
+               {
+                       if (g_units[i] != NULL)
+                               dv_unit_terminate( g_units[i] );
+               }
+
+               /* set the property */
+               strncpy( cmd_arg->root_dir, value, 1023 );
+
+               /* add a trailing slash if needed */
+               if ( cmd_arg->root_dir[ len - 1 ] != '/')
+               {
+                       cmd_arg->root_dir[ len ] = '/';
+                       cmd_arg->root_dir[ len + 1 ] = '\0';
+               }
+       }
+       else
+               return RESPONSE_OUT_OF_RANGE;
+       
+       return RESPONSE_SUCCESS;
+}
+
+/** Get a server configuration property.
+*/
+
+response_codes dv1394d_get_global_property( command_argument cmd_arg )
+{
+       char *key = (char*) cmd_arg->argument;
+
+       if ( strncasecmp( key, "root", 1024) == 0 )
+       {
+               dv_response_write( cmd_arg->response, cmd_arg->root_dir, strlen(cmd_arg->root_dir) );
+               return RESPONSE_SUCCESS_1;
+       }
+       else
+               return RESPONSE_OUT_OF_RANGE;
+       
+       return RESPONSE_SUCCESS;
+}
+
+/** IEEE 1394 Bus Reset handler 
+
+    This is included here for now due to all the unit management involved.
+*/
+
+static int reset_handler( raw1394handle_t h, unsigned int generation )
+{
+       int i, j, count, retry = 3;
+       int port = (int) raw1394_get_userdata( h );
+       
+       raw1394_update_generation( h, generation );
+       dv1394d_log( LOG_NOTICE, "bus reset on port %d", port );
+
+       while ( retry-- > 0 ) 
+       {
+               raw1394handle_t handle = raw1394_open( port );
+               count = raw1394_get_nodecount( handle );
+               
+               if ( count > 0 )
+               {
+                       dv1394d_log( LOG_DEBUG, "bus reset, checking units" );
+                       
+                       /* suspend all units on this port */
+                       for ( j = MAX_UNITS; j > 0; j-- )
+                       {
+                               if ( g_units[ j-1 ] != NULL && dv_unit_get_port( g_units[ j-1 ] ) == port )
+                                       dv_unit_suspend( g_units[ j-1 ] );
+                       }
+                       dv1394d_log( LOG_DEBUG, "All units are now stopped" );
+                       
+                       /* restore units with known guid, take others offline */
+                       for ( j = 0; j < MAX_UNITS; j++ )
+                       {
+                               if ( g_units[j] != NULL && 
+                                       ( dv_unit_get_port( g_units[ j ] ) == port || dv_unit_get_port( g_units[ j ] ) == -1 ) )
+                               {
+                                       int found = 0;
+                                       for ( i = 0; i < count; i++ )
+                                       {
+                                               octlet_t guid;
+                                               dv1394d_log( LOG_DEBUG, "attempting to get guid for node %d", i );
+                                               guid = rom1394_get_guid( handle, i );
+                                               if ( guid == g_units[ j ]->guid )
+                                               {
+                                                       dv1394d_log( LOG_NOTICE, "unit with GUID %08x%08x found", 
+                                                               (quadlet_t) (g_units[j]->guid>>32), (quadlet_t) (g_units[j]->guid & 0xffffffff));
+                                                       if ( dv_unit_is_offline( g_units[ j ] ) )
+                                                               dv_unit_online( g_units[ j ] );
+                                                       else
+                                                               dv_unit_restore( g_units[ j ] );
+                                                       found = 1;
+                                                       break;
+                                               }
+                                       }
+                                       if ( found == 0 )
+                                               dv_unit_offline( g_units[ j ] );
+                               }
+                       }
+                       dv1394d_log( LOG_DEBUG, "completed bus reset handler");
+                       raw1394_close( handle );
+                       return 0;
+               }
+               raw1394_close( handle );
+       }
+       dv1394d_log( LOG_CRIT, "raw1394 reported zero nodes on the bus!" );
+       return 0;
+}
+
+
+/** One pthread per IEEE 1394 port
+*/
+
+static pthread_t raw1394service_thread[4];
+
+/** One raw1394 handle for each pthread/port
+*/
+
+static raw1394handle_t raw1394service_handle[4];
+
+/** The service thread that polls raw1394 for new events.
+*/
+
+static void* raw1394_service( void *arg )
+{
+       raw1394handle_t handle = (raw1394handle_t) arg;
+       struct pollfd raw1394_poll;
+       raw1394_poll.fd = raw1394_get_fd( handle );
+       raw1394_poll.events = POLLIN;
+       raw1394_poll.revents = 0;
+       while ( 1 )
+       {
+               if ( poll( &raw1394_poll, 1, 200) > 0 )
+               {
+                       if ( (raw1394_poll.revents & POLLIN) 
+                                       || (raw1394_poll.revents & POLLPRI) )
+                               raw1394_loop_iterate( handle );
+               }
+               pthread_testcancel();
+       }
+       
+}
+
+
+/** Start the raw1394 service threads for handling bus reset.
+
+    One thread is launched per port on the system.
+*/
+
+void raw1394_start_service_threads( void )
+{
+       int port;
+       for ( port = 0; port < raw1394_get_num_ports(); port++ )
+       {
+               raw1394service_handle[port] = raw1394_open( port );
+               raw1394_set_bus_reset_handler( raw1394service_handle[port], reset_handler );
+               pthread_create( &(raw1394service_thread[port]), NULL, raw1394_service, raw1394service_handle[port] );
+       }
+       for ( ; port < 4; port++ )
+               raw1394service_handle[port] = NULL;
+}
+
+/** Shutdown all the raw1394 service threads.
+*/
+
+void raw1394_stop_service_threads( void )
+{
+       int i;
+       for ( i = 0; i < 4; i++ )
+       {
+               if ( raw1394service_handle[i] != NULL )
+               {
+                       pthread_cancel( raw1394service_thread[i] );
+                       pthread_join( raw1394service_thread[i], NULL );
+                       raw1394_close( raw1394service_handle[i] );
+               }
+       }
+}
+
+
diff --git a/src/miracle/miracle_commands.h b/src/miracle/miracle_commands.h
new file mode 100644 (file)
index 0000000..6c60d7d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * global_commands.h
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef _GLOBAL_COMMANDS_H_
+#define _GLOBAL_COMMANDS_H_
+
+#include <dv1394status.h>
+#include "dvunit.h"
+#include "dvconnection.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+dv_unit dv1394d_get_unit( int );
+void dv1394d_delete_unit( int );
+void dv1394d_delete_all_units( void );
+int dv1394d_unit_status( int n, dv1394_status status, int root_offset );
+void raw1394_start_service_threads( void );
+void raw1394_stop_service_threads( void );
+
+extern response_codes dv1394d_add_unit( command_argument );
+extern response_codes dv1394d_list_nodes( command_argument );
+extern response_codes dv1394d_list_units( command_argument );
+extern response_codes dv1394d_list_clips( command_argument );
+extern response_codes dv1394d_set_global_property( command_argument );
+extern response_codes dv1394d_get_global_property( command_argument );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/miracle/miracle_connection.c b/src/miracle/miracle_connection.c
new file mode 100644 (file)
index 0000000..6c65e35
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * dvconnection.c -- DV Connection Handler
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+#include <netdb.h>
+#include <sys/socket.h> 
+#include <arpa/inet.h>
+
+/* Application header files */
+#include "global_commands.h"
+#include "dvconnection.h"
+#include "dvsocket.h"
+#include "dvserver.h"
+#include "log.h"
+
+/** This is a generic replacement for fgets which operates on a file
+   descriptor. Unlike fgets, we can also specify a line terminator. Maximum
+   of (max - 1) chars can be read into buf from fd. If we reach the
+   end-of-file, *eof_chk is set to 1. 
+*/
+
+int fdgetline( int fd, char *buf, int max, char line_terminator, int *eof_chk )
+{
+       int count = 0;
+       char tmp [1];
+       *eof_chk = 0;
+       
+       if (fd)
+               while (count < max - 1) {
+                       if (read (fd, tmp, 1) > 0) {
+                               if (tmp [0] != line_terminator)
+                                       buf [count++] = tmp [0];
+                               else
+                                       break;
+
+/* Is it an EOF character (ctrl-D, i.e. ascii 4)? If so we definitely want
+   to break. */
+
+                               if (tmp [0] == 4) {
+                                       *eof_chk = 1;
+                                       break;
+                               }
+                       } else {
+                               *eof_chk = 1;
+                               break;
+                       }
+               }
+               
+       buf [count] = '\0';
+       
+       return count;
+}
+
+static int connection_initiate( int );
+static int connection_send( int, dv_response );
+static int connection_read( int, char *, int );
+static void connection_close( int );
+
+static int connection_initiate( int fd )
+{
+       int error = 0;
+       dv_response response = dv_response_init( );
+       dv_response_set_error( response, 100, "VTR Ready" );
+       error = connection_send( fd, response );
+       dv_response_close( response );
+       return error;
+}
+
+static int connection_send( int fd, dv_response response )
+{
+       int error = 0;
+       int index = 0;
+       int code = dv_response_get_error_code( response );
+
+       if ( code != -1 )
+       {
+               int items = dv_response_count( response );
+
+               if ( items == 0 )
+                       dv_response_set_error( response, 500, "Unknown error" );
+
+               if ( code == 200 && items > 2 )
+                       dv_response_set_error( response, 201, "OK" );
+               else if ( code == 200 && items > 1 )
+                       dv_response_set_error( response, 202, "OK" );
+
+               code = dv_response_get_error_code( response );
+               items = dv_response_count( response );
+
+               for ( index = 0; !error && index < items; index ++ )
+               {
+                       char *line = dv_response_get_line( response, index );
+                       int length = strlen( line );
+                       if ( length == 0 && index != dv_response_count( response ) - 1 && write( fd, " ", 1 ) != 1 )
+                               error = -1;
+                       else if ( length > 0 && write( fd, line, length ) != length )
+                               error = -1;
+                       if ( write( fd, "\r\n", 2 ) != 2 )
+                               error = -1;                     
+               }
+
+               if ( ( code == 201 || code == 500 ) && strcmp( dv_response_get_line( response, items - 1 ), "" ) )
+                       write( fd, "\r\n", 2 );
+       }
+       else
+       {
+               char *message = "500 Empty Response\r\n\r\n";
+               write( fd, message, strlen( message ) );
+       }
+
+       return error;
+}
+
+static int connection_read( int fd, char *command, int length )
+{
+       int eof_chk;
+       int nchars = fdgetline( fd, command, length, '\n', &eof_chk );
+       char *cr = strchr( command, '\r');
+       if ( cr != NULL ) 
+               cr[0] = '\0';
+       if ( eof_chk || strncmp( command, "BYE", 3 ) == 0 ) 
+               nchars = 0;
+       return nchars;
+}
+
+int connection_status( int fd, dv1394_notifier notifier )
+{
+       int error = 0;
+       int index = 0;
+       dv1394_status_t status;
+       char text[ 10240 ];
+       dv_socket socket = dv_socket_init_fd( fd );
+       
+       for ( index = 0; !error && index < MAX_UNITS; index ++ )
+       {
+               dv1394_notifier_get( notifier, &status, index );
+               dv1394_status_serialise( &status, text, sizeof( text ) );
+               error = dv_socket_write_data( socket, text, strlen( text )  ) != strlen( text );
+       }
+
+       while ( !error )
+       {
+               if ( dv1394_notifier_wait( notifier, &status ) == 0 )
+               {
+                       dv1394_status_serialise( &status, text, sizeof( text ) );
+                       error = dv_socket_write_data( socket, text, strlen( text ) ) != strlen( text );
+               }
+               else
+               {
+                       struct timeval tv = { 0, 0 };
+                       fd_set rfds;
+
+                   FD_ZERO( &rfds );
+                   FD_SET( fd, &rfds );
+
+                       if ( select( socket->fd + 1, &rfds, NULL, NULL, &tv ) )
+                               error = 1;
+               }
+       }
+
+       dv_socket_close( socket );
+       
+       return error;
+}
+
+static void connection_close( int fd )
+{
+       close( fd );
+}
+
+void *parser_thread( void *arg )
+{
+       struct hostent *he;
+       connection_t *connection = arg;
+       char address[ 512 ];
+       char command[ 1024 ];
+       int fd = connection->fd;
+       dv_parser parser = connection->parser;
+       dv_response response = NULL;
+
+       /* We definitely want to ignore broken pipes. */
+    signal( SIGPIPE, SIG_IGN );
+
+       /* Get the connecting clients ip information */
+       he = gethostbyaddr( (char *) &( connection->sin.sin_addr.s_addr ), sizeof(u_int32_t), AF_INET); 
+       if ( he != NULL )
+               strcpy( address, he->h_name );
+       else
+               inet_ntop( AF_INET, &( connection->sin.sin_addr.s_addr), address, 32 );
+
+       dv1394d_log( LOG_NOTICE, "Connection established with %s (%d)", address, fd );
+
+       /* Execute the commands received. */
+       if ( connection_initiate( fd ) == 0 )
+       {
+               int error = 0;
+
+               while( !error && connection_read( fd, command, 1024 ) )
+               {
+                       if ( strncmp( command, "STATUS", 6 ) )
+                       {
+                               response = dv_parser_execute( parser, command );
+                               dv1394d_log( LOG_INFO, "%s \"%s\" %d", address, command, dv_response_get_error_code( response ) );
+                               error = connection_send( fd, response );
+                               dv_response_close( response );
+                       }
+                       else
+                       {
+                               error = connection_status( fd, dv_parser_get_notifier( parser ) );
+                       }
+               }
+       }
+
+       /* Free the resources associated with this connection. */
+       connection_close( fd );
+
+       dv1394d_log( LOG_NOTICE, "Connection with %s (%d) closed", address, fd );
+
+       free( connection );
+
+       return NULL;
+}
diff --git a/src/miracle/miracle_connection.h b/src/miracle/miracle_connection.h
new file mode 100644 (file)
index 0000000..1c5d00b
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * dvconnection.h -- DV Connection Handler
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DV_CONNECTION_H_
+#define _DV_CONNECTION_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <dvparser.h>
+#include <dvtokeniser.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Connection structure
+*/
+
+typedef struct 
+{
+       int fd;
+       struct sockaddr_in sin;
+       dv_parser parser;
+} 
+connection_t;
+
+/** Enumeration for responses.
+*/
+
+typedef enum 
+{
+       RESPONSE_SUCCESS = 200,
+       RESPONSE_SUCCESS_N = 201,
+       RESPONSE_SUCCESS_1 = 202,
+       RESPONSE_UNKNOWN_COMMAND = 400,
+       RESPONSE_TIMEOUT = 401,
+       RESPONSE_MISSING_ARG = 402,
+       RESPONSE_INVALID_UNIT = 403,
+       RESPONSE_BAD_FILE = 404,
+       RESPONSE_OUT_OF_RANGE = 405,
+       RESPONSE_TOO_MANY_FILES = 406,
+       RESPONSE_ERROR = 500
+} 
+response_codes;
+
+/* the following struct is passed as the single argument 
+   to all command callback functions */
+
+typedef struct 
+{
+       dv_parser    parser;
+       dv_response  response;
+       dv_tokeniser tokeniser;
+       char         *command;
+       int           unit;
+       void         *argument;
+       char         *root_dir;
+} 
+command_argument_t, *command_argument;
+
+/* A handler is defined as follows. */
+typedef int (*command_handler_t) ( command_argument );
+
+
+extern void *parser_thread( void *arg );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/miracle/miracle_local.c b/src/miracle/miracle_local.c
new file mode 100644 (file)
index 0000000..fce4ab2
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * dvlocal.c -- Local dv1394d Parser
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* System header files */
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+/* Library header files */
+#include <dvutil.h>
+
+/* Application header files */
+#include <dvclipfactory.h>
+#include <dvframepool.h>
+#include "dvlocal.h"
+#include "dvconnection.h"
+#include "global_commands.h"
+#include "unit_commands.h"
+#include "log.h"
+#include "raw1394util.h"
+
+/** Private dv_local structure.
+*/
+
+typedef struct
+{
+       dv_parser parser;
+       char root_dir[1024];
+}
+*dv_local, dv_local_t;
+
+/** Forward declarations.
+*/
+
+static dv_response dv_local_connect( dv_local );
+static dv_response dv_local_execute( dv_local, char * );
+static void dv_local_close( dv_local );
+response_codes print_help( command_argument arg );
+response_codes dv1394d_run( command_argument arg );
+response_codes dv1394d_shutdown( command_argument arg );
+
+/** DV Parser constructor.
+*/
+
+dv_parser dv_parser_init_local( )
+{
+       dv_parser parser = malloc( sizeof( dv_parser_t ) );
+       dv_local local = malloc( sizeof( dv_local_t ) );
+
+       if ( parser != NULL )
+       {
+               memset( parser, 0, sizeof( dv_parser_t ) );
+
+               parser->connect = (parser_connect)dv_local_connect;
+               parser->execute = (parser_execute)dv_local_execute;
+               parser->close = (parser_close)dv_local_close;
+               parser->real = local;
+
+               if ( local != NULL )
+               {
+                       memset( local, 0, sizeof( dv_local_t ) );
+                       local->parser = parser;
+                       local->root_dir[0] = '/';
+               }
+       }
+       return parser;
+}
+
+/** response status code/message pair 
+*/
+
+typedef struct 
+{
+       int code;
+       char *message;
+} 
+responses_t;
+
+/** response messages 
+*/
+
+static responses_t responses [] = 
+{
+       {RESPONSE_SUCCESS, "OK"},
+       {RESPONSE_SUCCESS_N, "OK"},
+       {RESPONSE_SUCCESS_1, "OK"},
+       {RESPONSE_UNKNOWN_COMMAND, "Unknown command"},
+       {RESPONSE_TIMEOUT, "Operation timed out"},
+       {RESPONSE_MISSING_ARG, "Argument missing"},
+       {RESPONSE_INVALID_UNIT, "Unit not found"},
+       {RESPONSE_BAD_FILE, "Failed to locate or open clip"},
+       {RESPONSE_OUT_OF_RANGE, "Argument value out of range"},
+       {RESPONSE_TOO_MANY_FILES, "Too many files open"},
+       {RESPONSE_ERROR, "Server Error"}
+};
+
+/** Argument types.
+*/
+
+typedef enum 
+{
+       ATYPE_NONE,
+       ATYPE_FLOAT,
+       ATYPE_STRING,
+       ATYPE_INT
+} 
+arguments_types;
+
+/** A command definition.
+*/
+
+typedef struct 
+{
+/* The command string corresponding to this operation (e.g. "play") */
+       char *command;
+/* The function associated with it */
+       response_codes (*operation) ( command_argument );
+/* a boolean to indicate if this is a unit or global command
+   unit commands require a unit identifier as first argument */
+       int is_unit;
+/* What type is the argument (RTTI :-) ATYPE_whatever */
+       int type;
+/* online help information */
+       char *help;
+} 
+command_t;
+
+/* The following define the queue of commands available to the user. The
+   first entry is the name of the command (the string which must be typed),
+   the second command is the function associated with it, the third argument
+   is for the type of the argument, and the last argument specifies whether
+   this is something which should be handled immediately or whether it
+   should be queued (only robot motion commands need to be queued). */
+
+static command_t vocabulary[] = 
+{
+       {"BYE", NULL, 0, ATYPE_NONE, "Terminates the session. Units are not removed and task queue is not flushed."},
+       {"HELP", print_help, 0, ATYPE_NONE, "Display this information!"},
+       {"NLS", dv1394d_list_nodes, 0, ATYPE_NONE, "List the AV/C nodes on the 1394 bus."},
+       {"UADD", dv1394d_add_unit, 0, ATYPE_STRING, "Create a new DV unit (virtual VTR) to transmit to receiver specified in GUID argument."},
+       {"ULS", dv1394d_list_units, 0, ATYPE_NONE, "Lists the units that have already been added to the server."},
+       {"CLS", dv1394d_list_clips, 0, ATYPE_STRING, "Lists the clips at directory name argument."},
+       {"SET", dv1394d_set_global_property, 0, ATYPE_STRING, "Set a server configuration property."},
+       {"GET", dv1394d_get_global_property, 0, ATYPE_STRING, "Get a server configuration property."},
+       {"RUN", dv1394d_run, 0, ATYPE_STRING, "Run a batch file." },
+       {"LIST", dv1394d_list, 1, ATYPE_NONE, "List the playlist associated to a unit."},
+       {"LOAD", dv1394d_load, 1, ATYPE_STRING, "Load clip specified in absolute filename argument."},
+       {"INSERT", dv1394d_insert, 1, ATYPE_STRING, "Insert a clip at the given clip index."},
+       {"REMOVE", dv1394d_remove, 1, ATYPE_NONE, "Remove a clip at the given clip index."},
+       {"CLEAN", dv1394d_clean, 1, ATYPE_NONE, "Clean a unit by removing all but the currently playing clip."},
+       {"MOVE", dv1394d_move, 1, ATYPE_INT, "Move a clip to another clip index."},
+       {"APND", dv1394d_append, 1, ATYPE_STRING, "Append a clip specified in absolute filename argument."},
+       {"PLAY", dv1394d_play, 1, ATYPE_NONE, "Play a loaded clip at speed -2000 to 2000 where 1000 = normal forward speed."},
+       {"STOP", dv1394d_stop, 1, ATYPE_NONE, "Stop a loaded and playing clip."},
+       {"PAUSE", dv1394d_pause, 1, ATYPE_NONE, "Pause a playing clip."},
+       {"REW", dv1394d_rewind, 1, ATYPE_NONE, "Rewind a unit. If stopped, seek to beginning of clip. If playing, play fast backwards."},
+       {"FF", dv1394d_ff, 1, ATYPE_NONE, "Fast forward a unit. If stopped, seek to beginning of clip. If playing, play fast forwards."},
+       {"STEP", dv1394d_step, 1, ATYPE_INT, "Step argument number of frames forward or backward."},
+       {"GOTO", dv1394d_goto, 1, ATYPE_INT, "Jump to frame number supplied as argument."},
+       {"SIN", dv1394d_set_in_point, 1, ATYPE_INT, "Set the IN point of the loaded clip to frame number argument. -1 = reset in point to 0"},
+       {"SOUT", dv1394d_set_out_point, 1, ATYPE_INT, "Set the OUT point of the loaded clip to frame number argument. -1 = reset out point to maximum."},
+       {"USTA", dv1394d_get_unit_status, 1, ATYPE_NONE, "Report information about the unit."},
+       {"USET", dv1394d_set_unit_property, 1, ATYPE_STRING, "Set a unit configuration property."},
+       {"UGET", dv1394d_get_unit_property, 1, ATYPE_STRING, "Get a unit configuration property."},
+       {"XFER", dv1394d_transfer, 1, ATYPE_STRING, "Transfer the unit's clip to another unit specified as argument."},
+       {"SHUTDOWN", dv1394d_shutdown, 0, ATYPE_NONE, "Shutdown the server."},
+       {NULL, NULL, 0, ATYPE_NONE, NULL}
+};
+
+/** Usage message 
+*/
+
+static char helpstr [] = 
+       "dv1394d -- A DV over IEEE 1394 TCP Server\n" 
+       "       Copyright (C) 2002-2003 Ushodaya Enterprises Limited\n"
+       "       Authors:\n"
+       "               Dan Dennedy <dan@dennedy.org>\n"
+       "               Charles Yates <charles.yates@pandora.be>\n"
+       "Available commands:\n";
+
+/** Lookup the response message for a status code.
+*/
+
+inline char *get_response_msg( int code )
+{
+       int i = 0;
+       for ( i = 0; responses[ i ].message != NULL && code != responses[ i ].code; i ++ ) ;
+       return responses[ i ].message;
+}
+
+/** Tell the user the dv1394d command set
+*/
+
+response_codes print_help( command_argument cmd_arg )
+{
+       int i = 0;
+       
+       dv_response_printf( cmd_arg->response, 10240, "%s", helpstr );
+       
+       for ( i = 0; vocabulary[ i ].command != NULL; i ++ )
+               dv_response_printf( cmd_arg->response, 1024,
+                                                       "%-10.10s%s\n", 
+                                                       vocabulary[ i ].command, 
+                                                       vocabulary[ i ].help );
+
+       dv_response_printf( cmd_arg->response, 2, "\n" );
+
+       return RESPONSE_SUCCESS_N;
+}
+
+/** Execute a batch file.
+*/
+
+response_codes dv1394d_run( command_argument cmd_arg )
+{
+       dv_response temp = dv_parser_run( cmd_arg->parser, (char *)cmd_arg->argument );
+
+       if ( temp != NULL )
+       {
+               int index = 0;
+
+               dv_response_set_error( cmd_arg->response, 
+                                                          dv_response_get_error_code( temp ),
+                                                          dv_response_get_error_string( temp ) );
+
+               for ( index = 1; index < dv_response_count( temp ); index ++ )
+                       dv_response_printf( cmd_arg->response, 10240, "%s\n", dv_response_get_line( temp, index ) );
+
+               dv_response_close( temp );
+       }
+
+       return dv_response_get_error_code( cmd_arg->response );
+}
+
+response_codes dv1394d_shutdown( command_argument cmd_arg )
+{
+       exit( 0 );
+       return RESPONSE_SUCCESS;
+}
+
+/** Processes 'thread' id
+*/
+
+static pthread_t self;
+
+/* Signal handler to deal with various shutdown signals. Basically this
+   should clean up and power down the motor. Note that the death of any
+   child thread will kill all thrads. */
+
+void signal_handler( int sig )
+{
+       if ( pthread_equal( self, pthread_self( ) ) )
+       {
+
+#ifdef _GNU_SOURCE
+               dv1394d_log( LOG_DEBUG, "Received %s - shutting down.", strsignal(sig) );
+#else
+               dv1394d_log( LOG_DEBUG, "Received signal %i - shutting down.", sig );
+#endif
+
+               exit(EXIT_SUCCESS);
+       }
+}
+
+/** Local 'connect' function.
+*/
+
+static dv_response dv_local_connect( dv_local local )
+{
+       dv_response response = dv_response_init( );
+
+       self = pthread_self( );
+
+       dv_response_set_error( response, 100, "VTR Ready" );
+
+       signal( SIGHUP, signal_handler );
+       signal( SIGINT, signal_handler );
+       signal( SIGTERM, signal_handler );
+       signal( SIGSTOP, signal_handler );
+       signal( SIGCHLD, SIG_IGN );
+       
+       raw1394_reconcile_bus();
+       /* Start the raw1394 service threads for handling bus resets */
+       raw1394_start_service_threads();
+
+       return response;
+}
+
+/** Set the error and determine the message associated to this command.
+*/
+
+void dv_command_set_error( command_argument cmd, response_codes code )
+{
+       dv_response_set_error( cmd->response, code, get_response_msg( code ) );
+}
+
+/** Parse the unit argument.
+*/
+
+int dv_command_parse_unit( command_argument cmd, int argument )
+{
+       int unit = -1;
+       char *string = dv_tokeniser_get_string( cmd->tokeniser, argument );
+       if ( string != NULL && ( string[ 0 ] == 'U' || string[ 0 ] == 'u' ) && strlen( string ) > 1 )
+               unit = atoi( string + 1 );
+       return unit;
+}
+
+/** Parse a normal argument.
+*/
+
+void *dv_command_parse_argument( command_argument cmd, int argument, arguments_types type )
+{
+       void *ret = NULL;
+       char *value = dv_tokeniser_get_string( cmd->tokeniser, argument );
+
+       if ( value != NULL )
+       {
+               switch( type )
+               {
+                       case ATYPE_NONE:
+                               break;
+
+                       case ATYPE_FLOAT:
+                               ret = malloc( sizeof( float ) );
+                               if ( ret != NULL )
+                                       *( float * )ret = atof( value );
+                               break;
+
+                       case ATYPE_STRING:
+                               ret = strdup( value );
+                               break;
+                                       
+                       case ATYPE_INT:
+                               ret = malloc( sizeof( int ) );
+                               if ( ret != NULL )
+                                       *( int * )ret = atoi( value );
+                               break;
+               }
+       }
+
+       return ret;
+}
+
+/** Get the error code - note that we simply the success return.
+*/
+
+response_codes dv_command_get_error( command_argument cmd )
+{
+       response_codes ret = dv_response_get_error_code( cmd->response );
+       if ( ret == RESPONSE_SUCCESS_N || ret == RESPONSE_SUCCESS_1 )
+               ret = RESPONSE_SUCCESS;
+       return ret;
+}
+
+/** Execute the command.
+*/
+
+static dv_response dv_local_execute( dv_local local, char *command )
+{
+       command_argument_t cmd;
+       cmd.parser = local->parser;
+       cmd.response = dv_response_init( );
+       cmd.tokeniser = dv_tokeniser_init( );
+       cmd.command = command;
+       cmd.unit = -1;
+       cmd.argument = NULL;
+       cmd.root_dir = local->root_dir;
+
+       /* Set the default error */
+       dv_command_set_error( &cmd, RESPONSE_UNKNOWN_COMMAND );
+
+       /* Parse the command */
+       if ( dv_tokeniser_parse_new( cmd.tokeniser, command, " " ) > 0 )
+       {
+               int index = 0;
+               char *value = dv_tokeniser_get_string( cmd.tokeniser, 0 );
+               int found = 0;
+
+               /* Strip quotes from all tokens */
+               for ( index = 0; index < dv_tokeniser_count( cmd.tokeniser ); index ++ )
+                       dv_util_strip( dv_tokeniser_get_string( cmd.tokeniser, index ), '\"' );
+
+               /* Search the vocabulary array for value */
+               for ( index = 1; !found && vocabulary[ index ].command != NULL; index ++ )
+                       if ( ( found = !strcasecmp( vocabulary[ index ].command, value ) ) )
+                               break;
+
+               /* If we found something, the handle the args and call the handler. */
+               if ( found )
+               {
+                       int position = 1;
+
+                       dv_command_set_error( &cmd, RESPONSE_SUCCESS );
+
+                       if ( vocabulary[ index ].is_unit )
+                       {
+                               cmd.unit = dv_command_parse_unit( &cmd, position );
+                               if ( cmd.unit == -1 )
+                                       dv_command_set_error( &cmd, RESPONSE_MISSING_ARG );
+                               position ++;
+                       }
+
+                       if ( dv_command_get_error( &cmd ) == RESPONSE_SUCCESS )
+                       {
+                               cmd.argument = dv_command_parse_argument( &cmd, position, vocabulary[ index ].type );
+                               if ( cmd.argument == NULL && vocabulary[ index ].type != ATYPE_NONE )
+                                       dv_command_set_error( &cmd, RESPONSE_MISSING_ARG );
+                               position ++;
+                       }
+
+                       if ( dv_command_get_error( &cmd ) == RESPONSE_SUCCESS )
+                       {
+                               response_codes error = vocabulary[ index ].operation( &cmd );
+                               dv_command_set_error( &cmd, error );
+                       }
+
+                       free( cmd.argument );
+               }
+       }
+
+       dv_tokeniser_close( cmd.tokeniser );
+
+       return cmd.response;
+}
+
+/** Close the parser.
+*/
+
+static void dv_local_close( dv_local local )
+{
+       raw1394_stop_service_threads();
+       dv1394d_delete_all_units();
+       pthread_kill_other_threads_np();
+       dv1394d_log( LOG_DEBUG, "Clean shutdown." );
+       free( local );
+       dv_clip_factory_close( );
+       dv_frame_pool_close( );
+}
diff --git a/src/miracle/miracle_local.h b/src/miracle/miracle_local.h
new file mode 100644 (file)
index 0000000..fbbe444
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * dvlocal.h -- Local dv1394d Parser
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _DV_LOCAL_H_
+#define _DV_LOCAL_H_
+
+/* Application header files */
+#include <dvparser.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Local parser API.
+*/
+
+extern dv_parser dv_parser_init_local( );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/miracle/miracle_log.c b/src/miracle/miracle_log.c
new file mode 100644 (file)
index 0000000..cdb5d82
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * log.h -- logging facility implementation
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdarg.h>
+#include <syslog.h>
+#include <stdio.h>
+
+#include "log.h"
+
+static int log_output = log_stderr;
+static int threshold = LOG_DEBUG;
+
+void
+dv1394d_log_init( enum log_output method, int new_threshold )
+{
+       log_output = method;
+       threshold = new_threshold;
+       if (method == log_syslog)
+               openlog( "dv1394d", LOG_CONS, LOG_DAEMON );
+
+}
+
+void
+dv1394d_log( int priority, char *format, ... )
+{
+       va_list list;
+       va_start( list, format );
+       if ( LOG_PRI(priority) <= threshold )
+       {
+               if ( log_output == log_syslog )
+               {
+                               vsyslog( priority, format, list );
+               }
+               else
+               {
+                       char line[1024];
+                       if ( snprintf( line, 1024, "(%d) %s\n", priority, format ) != 0 )
+                               vfprintf( stderr, line, list );
+               }
+       }
+       va_end( list );
+}
diff --git a/src/miracle/miracle_log.h b/src/miracle/miracle_log.h
new file mode 100644 (file)
index 0000000..04505e9
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * log.h -- logging facility header
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include <syslog.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+enum log_output {
+       log_stderr,
+       log_syslog
+};
+
+void dv1394d_log_init( enum log_output method, int threshold );
+void dv1394d_log( int priority, char *format, ... );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/miracle/miracle_server.c b/src/miracle/miracle_server.c
new file mode 100644 (file)
index 0000000..d4f886b
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * dvserver.c -- DV Server
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <string.h>
+#include <netinet/in.h>
+#include "log.h"
+#include <netdb.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+/* Application header files */
+#include "dvserver.h"
+#include "dvconnection.h"
+#include "dvlocal.h"
+#include "log.h"
+#include <dvremote.h>
+#include <dvtokeniser.h>
+
+/** Initialise a server structure.
+*/
+
+dv_server dv_server_init( char *id )
+{
+       dv_server server = malloc( sizeof( dv_server_t ) );
+       if ( server != NULL )
+       {
+               memset( server, 0, sizeof( dv_server_t ) );
+               server->id = id;
+               server->port = DEFAULT_TCP_PORT;
+               server->socket = -1;
+       }
+       return server;
+}
+
+/** Set the port of the server.
+*/
+
+void dv_server_set_port( dv_server server, int port )
+{
+       server->port = port;
+}
+
+void dv_server_set_proxy( dv_server server, char *proxy )
+{
+       dv_tokeniser tokeniser = dv_tokeniser_init( );
+       server->proxy = 1;
+       server->remote_port = DEFAULT_TCP_PORT;
+       dv_tokeniser_parse_new( tokeniser, proxy, ":" );
+       strcpy( server->remote_server, dv_tokeniser_get_string( tokeniser, 0 ) );
+       if ( dv_tokeniser_count( tokeniser ) == 2 )
+               server->remote_port = atoi( dv_tokeniser_get_string( tokeniser, 1 ) );
+       dv_tokeniser_close( tokeniser );
+}
+
+/** Wait for a connection.
+*/
+
+static int dv_server_wait_for_connect( dv_server server )
+{
+    struct timeval tv;
+    fd_set rfds;
+
+    /* Wait for a 1 second. */
+    tv.tv_sec = 1;
+    tv.tv_usec = 0;
+
+    FD_ZERO( &rfds );
+    FD_SET( server->socket, &rfds );
+
+    return select( server->socket + 1, &rfds, NULL, NULL, &tv);
+}
+
+/** Run the server thread.
+*/
+
+static void *dv_server_run( void *arg )
+{
+       dv_server server = arg;
+       pthread_t cmd_parse_info;
+       connection_t *tmp = NULL;
+       pthread_attr_t thread_attributes;
+       int socksize;
+
+       socksize = sizeof( struct sockaddr );
+
+       dv1394d_log( LOG_NOTICE, "%s version %s listening on port %i", server->id, VERSION, server->port );
+
+       /* Create the initial thread. We want all threads to be created detached so
+          their resources get freed automatically. (CY: ... hmmph...) */
+       pthread_attr_init( &thread_attributes );
+       pthread_attr_setdetachstate( &thread_attributes, PTHREAD_CREATE_DETACHED );
+       pthread_attr_init( &thread_attributes );
+       pthread_attr_setinheritsched( &thread_attributes, PTHREAD_INHERIT_SCHED );
+       /* pthread_attr_setschedpolicy( &thread_attributes, SCHED_RR ); */
+
+       while ( !server->shutdown )
+       {
+               /* Wait for a new connection. */
+               if ( dv_server_wait_for_connect( server ) )
+               {
+                       /* Create a new block of data to hold a copy of the incoming connection for
+                          our server thread. The thread should free this when it terminates. */
+
+                       tmp = (connection_t*) malloc( sizeof(connection_t) );
+                       tmp->parser = server->parser;
+                       tmp->fd = accept( server->socket, (struct sockaddr*) &(tmp->sin), &socksize );
+
+                       /* Pass the connection to a parser thread :-/ */
+                       if ( tmp->fd != -1 )
+                               pthread_create( &cmd_parse_info, &thread_attributes, parser_thread, tmp );
+               }
+       }
+
+       dv1394d_log( LOG_NOTICE, "%s version %s server terminated.", server->id, VERSION );
+
+       return NULL;
+}
+
+/** Execute the server thread.
+*/
+
+int dv_server_execute( dv_server server )
+{
+       int error = 0;
+       dv_response response = NULL;
+       int index = 0;
+       struct sockaddr_in ServerAddr;
+       int flag = 1;
+
+       ServerAddr.sin_family = AF_INET;
+       ServerAddr.sin_port = htons( server->port );
+       ServerAddr.sin_addr.s_addr = INADDR_ANY;
+       
+       /* Create socket, and bind to port. Listen there. Backlog = 5
+          should be sufficient for listen (). */
+       server->socket = socket( AF_INET, SOCK_STREAM, 0 );
+
+       if ( server->socket == -1 )
+       {
+               server->shutdown = 1;
+               perror( "socket" );
+               dv1394d_log( LOG_ERR, "%s unable to create socket.", server->id );
+               return -1;
+       }
+
+    setsockopt( server->socket, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof( int ) );
+
+       if ( bind( server->socket, (struct sockaddr *) &ServerAddr, sizeof (ServerAddr) ) != 0 )
+       {
+               server->shutdown = 1;
+               perror( "bind" );
+               dv1394d_log( LOG_ERR, "%s unable to bind to port %d.", server->id, server->port );
+               return -1;
+       }
+
+       if ( listen( server->socket, 5 ) != 0 )
+       {
+               server->shutdown = 1;
+               perror( "listen" );
+               dv1394d_log( LOG_ERR, "%s unable to listen on port %d.", server->id, server->port );
+               return -1;
+       }
+
+       fcntl( server->socket, F_SETFL, O_NONBLOCK );
+
+       if ( !server->proxy )
+       {
+               dv1394d_log( LOG_NOTICE, "Starting server on %d.", server->port );
+               server->parser = dv_parser_init_local( );
+       }
+       else
+       {
+               dv1394d_log( LOG_NOTICE, "Starting proxy for %s:%d on %d.", server->remote_server, server->remote_port, server->port );
+               server->parser = dv_parser_init_remote( server->remote_server, server->remote_port );
+       }
+
+       response = dv_parser_connect( server->parser );
+
+       if ( response != NULL && dv_response_get_error_code( response ) == 100 )
+       {
+               /* read configuration file */
+               if ( response != NULL && !server->proxy )
+               {
+                       dv_response_close( response );
+                       response = dv_parser_run( server->parser, "/etc/dv1394d.conf" );
+
+                       if ( dv_response_count( response ) > 1 )
+                       {
+                               if ( dv_response_get_error_code( response ) > 299 )
+                                       dv1394d_log( LOG_ERR, "Error evaluating server configuration. Processing stopped." );
+                               for ( index = 0; index < dv_response_count( response ); index ++ )
+                                       dv1394d_log( LOG_DEBUG, "%4d: %s", index, dv_response_get_line( response, index ) );
+                       }
+               }
+
+               if ( response != NULL )
+               {
+                       pthread_attr_t attr;
+                       int result;
+                       pthread_attr_init( &attr );
+                       pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
+                       pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
+                       pthread_attr_setschedpolicy( &attr, SCHED_FIFO );
+                       pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );
+                       dv_response_close( response );
+                       result = pthread_create( &server->thread, &attr, dv_server_run, server );
+                       if ( result )
+                       {
+                               dv1394d_log( LOG_WARNING, "Failed to schedule realtime (%s)", strerror(errno) );
+                               pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
+                               result = pthread_create( &server->thread, &attr, dv_server_run, server );
+                               if ( result )
+                               {
+                                       dv1394d_log( LOG_CRIT, "Failed to launch TCP listener thread" );
+                                       error = -1;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               dv1394d_log( LOG_ERR, "Error connecting to parser. Processing stopped." );
+               server->shutdown = 1;
+               error = -1;
+       }
+
+       return error;
+}
+
+/** Shutdown the server.
+*/
+
+void dv_server_shutdown( dv_server server )
+{
+       if ( server != NULL && !server->shutdown )
+       {
+               server->shutdown = 1;
+               pthread_join( server->thread, NULL );
+               dv_parser_close( server->parser );
+               close( server->socket );
+       }
+}
diff --git a/src/miracle/miracle_server.h b/src/miracle/miracle_server.h
new file mode 100644 (file)
index 0000000..96b22ce
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * dvserver.h -- DV Server
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DV_SERVER_H_
+#define _DV_SERVER_H_
+
+/* System header files */
+#include <pthread.h>
+
+/* Application header files */
+#include <dvparser.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Servers default port
+*/
+
+#define DEFAULT_TCP_PORT 5250
+
+/** Structure for the server
+*/
+
+typedef struct
+{
+       char *id;
+       int port;
+       int socket;
+       dv_parser parser;
+       pthread_t thread;
+       int shutdown;
+       int proxy;
+       char remote_server[ 50 ];
+       int remote_port;
+}
+*dv_server, dv_server_t;
+
+/** API for the server
+*/
+
+extern dv_server dv_server_init( char * );
+extern void dv_server_set_port( dv_server, int );
+extern void dv_server_set_proxy( dv_server, char * );
+extern int dv_server_execute( dv_server );
+extern void dv_server_shutdown( dv_server );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/miracle/miracle_unit.c b/src/miracle/miracle_unit.c
new file mode 100644 (file)
index 0000000..bc8adcf
--- /dev/null
@@ -0,0 +1,1100 @@
+/*
+ * dvunit.c -- DV Transmission Unit Implementation
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <libdv/dv1394.h>
+#include <libraw1394/raw1394.h>
+#include <libavc1394/avc1394_vcr.h>
+#include <sys/mman.h>
+
+#include "dvunit.h"
+#include "dvframe.h"
+#include "dvframepool.h"
+#include "dvqueue.h"
+#include "dvpump.h"
+#include "dverror.h"
+#include "dvplayer.h"
+#include "raw1394util.h"
+#include "log.h"
+#include "dvlocal.h"
+
+/* Forward references */
+static void dv_unit_status_communicate( dv_unit );
+
+/** dv1394 device file names based upon devfs default names. */
+
+static char *devices[4][4] = {
+       {
+       "/dev/ieee1394/dv/host0/NTSC/in",
+       "/dev/ieee1394/dv/host0/NTSC/out",
+       "/dev/ieee1394/dv/host0/PAL/in",
+       "/dev/ieee1394/dv/host0/PAL/out",
+       },{
+       "/dev/ieee1394/dv/host1/NTSC/in",
+       "/dev/ieee1394/dv/host1/NTSC/out",
+       "/dev/ieee1394/dv/host1/PAL/in",
+       "/dev/ieee1394/dv/host1/PAL/out"
+       },{
+       "/dev/ieee1394/dv/host2/NTSC/in",
+       "/dev/ieee1394/dv/host2/NTSC/out",
+       "/dev/ieee1394/dv/host2/PAL/in",
+       "/dev/ieee1394/dv/host2/PAL/out"
+       },{
+       "/dev/ieee1394/dv/host3/NTSC/in",
+       "/dev/ieee1394/dv/host3/NTSC/out",
+       "/dev/ieee1394/dv/host3/PAL/in",
+       "/dev/ieee1394/dv/host3/PAL/out"
+       }
+};
+
+static int device_count[4] = {0,0,0,0};
+
+/** Allocate a new DV transmission unit.
+
+    \param dv1394d_fd The file descriptor of a dv1394 device file to 
+                      use for transmission.
+    \param guid The node GUID of the receiving device.
+    \param channel The channel to use for transmission.
+    \return A new dv_unit handle.
+*/
+
+dv_unit dv_unit_init( octlet_t guid, int channel )
+{
+       dv_unit unit = malloc( sizeof( dv_unit_t ) );
+       if ( unit != NULL )
+       {
+               int node_id;
+               
+               memset( unit, 0, sizeof( dv_unit_t ) );
+               unit->guid = guid;
+               unit->buffer_size = 25;
+               unit->is_terminated = 1;
+               unit->channel = channel;
+               unit->dv1394_fd = -1;
+               unit->n_frames = DV1394_MAX_FRAMES / 2;
+               unit->n_fill = 1;
+
+               /* get a raw1394 handle for plug control */
+               if ( ( node_id = raw1394_find_node( &(unit->raw1394), guid ) ) != -1 )
+               {
+                       if ( dv_unit_online( unit ) == 1 )
+                               dv1394d_log( LOG_DEBUG, "Added online unit with GUID %08x%08x", 
+                                       (quadlet_t) (unit->guid>>32), (quadlet_t) (unit->guid & 0xffffffff) );
+                       else
+                       {
+                               dv_unit_close( unit );
+                               unit = NULL;
+                       }
+               }
+               else
+               {
+                       dv1394d_log( LOG_DEBUG, "Added offline unit with GUID %08x%08x", 
+                               (quadlet_t) (unit->guid>>32), (quadlet_t) (unit->guid & 0xffffffff) );
+               }
+       }
+       return unit;
+}
+
+/** Allow stdin to feed the unit (redundant now that senddv has been dropped).
+*/
+
+void dv_unit_allow_stdin( dv_unit unit, int flag )
+{
+       unit->allow_stdin = flag;
+}
+
+/** Override the default buffer/pump size - this must be done prior to the pumps
+       creation.
+*/
+
+void dv_unit_set_buffer_size( dv_unit unit, int size )
+{
+       if ( size > 0 )
+       {
+               if ( unit->pump == NULL )
+                       unit->buffer_size = size;
+               else
+                       unit->buffer_size = dv_pump_resize( unit->pump, size );
+       }
+}
+
+int dv_unit_get_buffer_size( dv_unit unit )
+{
+       return unit->buffer_size;
+}
+
+void dv_unit_set_n_frames( dv_unit unit, int size )
+{
+       if ( size > 0 && size <= DV1394_MAX_FRAMES / 2 )
+               unit->n_frames = size;
+}
+
+int dv_unit_get_n_frames( dv_unit unit )
+{
+       return unit->n_frames;
+}
+
+void dv_unit_set_n_fill( dv_unit unit, int size )
+{
+       unit->n_fill = size;
+}
+
+int dv_unit_get_n_fill( dv_unit unit )
+{
+       return unit->n_fill;
+}
+
+/** Set the notifier info
+*/
+
+void dv_unit_set_notifier( dv_unit this, dv1394_notifier notifier, char *root_dir )
+{
+       this->notifier = notifier;
+       this->root_dir = root_dir;
+       dv_unit_status_communicate( this );
+}
+
+/** Communicate the current status to all threads waiting on the notifier.
+*/
+
+static void dv_unit_status_communicate( dv_unit unit )
+{
+       if ( unit != NULL && unit->notifier != NULL && unit->root_dir != NULL )
+       {
+               dv1394_status_t status;
+               if ( dv_unit_get_status( unit, &status ) == 0 )
+                       if ( !( ( status.status == unit_playing || status.status == unit_paused ) &&
+                                       strcmp( status.clip, "" ) && 
+                                   !strcmp( status.tail_clip, "" ) && 
+                                       status.position == 0 && 
+                                       status.in == 0 && 
+                                       status.out == 0 ) )
+                               dv1394_notifier_put( unit->notifier, &status );
+       }
+}
+
+/** Load a clip into the unit clearing existing play list.
+
+    \todo error handling
+    \param unit A dv_unit handle.
+    \param clip The absolute file name of the clip to load.
+    \param in   The starting frame (-1 for 0)
+       \param out  The ending frame (-1 for maximum)
+*/
+
+dv_error_code dv_unit_load( dv_unit unit, const char *clip, long in, long out, int flush )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_error_code error = dv_player_get_error( player );
+       if ( error == dv_pump_ok )
+       {
+               error = dv_player_replace_file( player, (char*) clip, in, out, flush );
+               dv1394d_log( LOG_DEBUG, "loaded clip %s", clip );
+               if ( unit->is_terminated )
+                       dv_unit_status_communicate( unit );
+       }
+       return error;
+}
+
+dv_error_code dv_unit_insert( dv_unit unit, const char *clip, int index, long in, long out )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_error_code error = dv_player_get_error( player );
+       if ( error == dv_pump_ok )
+       {
+               error = dv_player_insert_file( player, (char*) clip, index, in, out );
+               dv1394d_log( LOG_DEBUG, "inserted clip %s", clip );
+               if ( unit->is_terminated )
+                       dv_unit_status_communicate( unit );
+       }
+       return error;
+}
+
+dv_error_code dv_unit_remove( dv_unit unit, int index )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_error_code error = dv_player_get_error( player );
+       if ( error == dv_pump_ok )
+       {
+               error = dv_player_remove_clip( player, index );
+               dv1394d_log( LOG_DEBUG, "removed clip %d", index );
+               if ( unit->is_terminated )
+                       dv_unit_status_communicate( unit );
+       }
+       return error;
+}
+
+dv_error_code dv_unit_clean( dv_unit unit )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_error_code error = dv_player_get_error( player );
+       if ( error == dv_pump_ok )
+       {
+               error = dv_player_clean( player );
+               dv1394d_log( LOG_DEBUG, "Cleaned playlist" );
+               if ( unit->is_terminated )
+                       dv_unit_status_communicate( unit );
+       }
+       return error;
+}
+
+dv_error_code dv_unit_move( dv_unit unit, int src, int dest )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_error_code error = dv_player_get_error( player );
+       if ( error == dv_pump_ok )
+       {
+               error = dv_player_move_clip( player, src, dest );
+               dv1394d_log( LOG_DEBUG, "moved clip %d to %d", src, dest );
+               if ( unit->is_terminated )
+                       dv_unit_status_communicate( unit );
+       }
+       return error;
+}
+
+/** Add a clip to the unit play list.
+
+    \todo error handling
+    \param unit A dv_unit handle.
+    \param clip The absolute file name of the clip to load.
+    \param in   The starting frame (-1 for 0)
+       \param out  The ending frame (-1 for maximum)
+*/
+
+dv_error_code dv_unit_append( dv_unit unit, const char *clip, long in, long out )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_error_code error = dv_player_add_file( player, (char*) clip, in, out );
+       dv_unit_status_communicate( unit );
+       return error;
+}
+
+void *output_cleanup( void *arg )
+{
+       dv_unit unit = arg;
+       if ( unit != NULL && unit->mmap != NULL )
+       {
+               unit->is_terminated = 1;
+               dv_unit_status_communicate( unit );
+               munmap( unit->mmap, unit->mmap_length );
+               /* this actually stops transmission as opposed to allowing the 
+                  last frame to loop in the OHCI DMA context. */
+               ioctl( unit->dv1394_fd, DV1394_SHUTDOWN, NULL );
+       }
+
+       return NULL;
+}
+
+/** The dv1394 transmission thread.
+
+    \param arg A dv_unit handle.
+*/
+
+static void *output( void *arg )
+{
+       dv_unit unit = arg;
+       dv_frame frames[ DV1394_MAX_FRAMES ];
+       int frames_dropped = 0; /* count of total frames dropped (repeated) */
+       struct dv1394_status status;
+       char errstr[64];
+       int n_fill = unit->n_fill;
+       int n_frames = unit->n_frames;
+       
+       /* Determine the number of frames to wait for/fill on each iteration */
+       if ( n_fill < 1 )
+               n_fill = 1;
+       else if ( n_fill > unit->n_frames )
+               n_fill = n_frames / 2;
+
+       unit->mmap = mmap( NULL,unit->mmap_length,PROT_WRITE,MAP_SHARED,unit->dv1394_fd,0 );
+       if ( unit->mmap == MAP_FAILED || unit->mmap == NULL )
+       {
+               perror( "mmap" );
+               return NULL;
+       }
+
+       pthread_cleanup_push( output_cleanup, (void *)arg );
+
+       while ( dv_pump_get_available_output_count( unit->pump ) || 
+               !( dv_unit_has_terminated( unit ) || dv_pump_has_terminated( unit->pump) ) )
+       {
+               int available = 0;
+
+               if ( ioctl( unit->dv1394_fd, DV1394_WAIT_FRAMES, n_fill ) < 0)
+                       perror( "DV1394_WAIT_FRAMES" );
+
+               pthread_testcancel();
+
+               /* update the status for the next iteration and detect dropped frames */
+               if ( ioctl( unit->dv1394_fd, DV1394_GET_STATUS, &status ) >= 0)
+               {
+                       pthread_testcancel();
+
+                       /*
+                       printf( "dv1394 status: active=%02d, #clear=%02d, first clear=%02d\n", 
+                               status.active_frame, status.n_clear_frames, status.first_clear_frame);
+                       */
+               
+                       /* report dropped frames */
+                       if( status.dropped_frames > 0 )
+                       {
+                               frames_dropped += status.dropped_frames;
+                               dv1394d_log( LOG_WARNING, "dv1394 repeated %d frames with %d available.", 
+                                                        status.dropped_frames, dv_pump_get_available_output_count( unit->pump ) );
+                       }
+
+                       available = dv_pump_get_output_block( unit->pump, (void **)frames, n_fill );
+
+                       dv_unit_status_communicate( unit );
+                       
+                       /* The only time we get 0 frames is when the unit is being stopped. */
+                       if ( available != 0 )
+                       {
+                               int size = dv_frame_size( frames[ 0 ] );
+                               int pos = status.first_clear_frame;
+                               int index = 0;
+
+                               for ( index = 0; index < available; index ++ )
+                                       memcpy( unit->mmap + ( ( pos + index ) % n_frames ) * size, dv_frame_data( frames[ index ] ), size );
+
+                               if ( ioctl( unit->dv1394_fd, DV1394_SUBMIT_FRAMES, available ) >= 0)
+                               {
+                                       for ( index = 0; index < available - 1; index ++ )
+                                       {
+                                               dv_frame_clear_error( frames[ index ] );
+                                               dv_frame_id_clear( dv_frame_get_id( frames[ index ] ) );
+                                       }                       
+                                       dv_pump_return_output_block( unit->pump );
+                                       pthread_testcancel();
+                               }
+                               else
+                               {
+                                       dv1394d_log( LOG_ERR, "failed to write frames to dv1394: %s.", strerror_r( errno, errstr, 63 ) );
+                                       dv_pump_terminate( unit->pump );
+                                       dv_pump_flush( unit->pump );
+                                       pthread_testcancel();
+                               }
+                       }
+               }
+               else
+               {
+                       dv1394d_log( LOG_ERR, "failed to get dv1394 status: %s.", strerror_r( errno, errstr, 63 ) );
+                       dv_pump_return_used_output( unit->pump );
+               }
+       }
+
+       if ( frames_dropped > 0 )
+               dv1394d_log( LOG_WARNING, "dv1394 repeated %d frames total during this transmission.", frames_dropped );
+
+       pthread_cleanup_pop( 1 );
+
+       return NULL;
+}
+
+/** Start playing the clip.
+
+    Start a dv-pump and commence dv1394 transmission.
+
+    \todo error handling
+    \param unit A dv_unit handle.
+    \param speed An integer that specifies the playback rate as a
+                 percentage multiplied by 100.
+*/
+
+void dv_unit_play( dv_unit_t *unit, int speed )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+
+       if ( unit->is_terminated == 1 && ( dv_player_get_total_frames( player ) > 0 || unit->allow_stdin ) )
+       {
+               int retval;
+               dv_frame frame = NULL;
+               struct dv1394_init setup =
+               {
+                       api_version: DV1394_API_VERSION,
+                       channel: unit->channel,
+                       /* this only sets the *requested* size of the ringbuffer,
+                          in frames */ 
+                       n_frames: unit->n_frames,
+                       /* we set the format later */
+                       cip_n: unit->dv1394_cip_n,
+                       cip_d: unit->dv1394_cip_d,
+                       syt_offset: unit->dv1394_syt_offset
+               };
+               pthread_attr_t attr;
+
+               if ( unit->in == NULL )
+               {
+                       if ( !unit->allow_stdin || dv_player_get_total_frames( player ) != 0 )
+                               unit->in = dv_player_get_dv_input( player );
+                       else
+                               unit->in = dv_input_init( unit->pump );
+               }
+               else
+               {
+                       dv_input_join_thread( unit->in );
+                       pthread_join( unit->out, NULL );
+               }
+
+               unit->is_terminated = 0;
+               dv_pump_restart( unit->pump );
+               dv_input_start_thread( unit->in );
+               dv_player_set_speed( player, (double) speed/1000.0 );
+
+               /* first we read a little data to see if this is PAL or NTSC
+                  so we can initialize dv1394 properly */
+               frame = dv_pump_get_available_output( unit->pump );
+       
+               /* initialize dv1394 */
+               setup.format = dv_frame_is_pal(frame) ? DV1394_PAL : DV1394_NTSC;
+               
+               retval = ioctl( unit->dv1394_fd, DV1394_INIT, &setup );
+               if (retval < 0)
+               {
+                       perror( "DV1394_INIT" );
+                       return;
+               }
+
+               unit->mmap_length = unit->n_frames * dv_frame_size( frame );
+
+               pthread_attr_init( &attr );
+               pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
+               pthread_attr_setinheritsched( &attr, PTHREAD_INHERIT_SCHED );
+               pthread_create( &unit->out, &attr, output, unit );
+       }
+       else 
+       {
+               dv_player_set_speed( player, (double) speed/1000.0 );
+       }
+       dv_unit_status_communicate( unit );
+}
+
+/** Stop playback.
+
+    Terminates the dv_pump and halts dv1394 transmission.
+
+    \param unit A dv_unit handle.
+*/
+
+void dv_unit_terminate( dv_unit unit )
+{
+       unit->is_terminated = 1;
+       if ( unit->pump != NULL )
+       {
+               dv_pump_terminate( unit->pump );
+               dv_pump_flush( unit->pump );
+       }
+}
+
+/** Query the status of unit playback.
+
+    \param unit A dv_unit handle.
+    \return 1 if the unit is not playing, 0 if playing.
+*/
+
+int dv_unit_has_terminated( dv_unit unit )
+{
+       return unit->is_terminated;
+}
+
+/** Get the dv_player from the dv_unit.
+
+    \param unit A dv_unit handle.
+    \return A dv_player handle.
+*/
+
+dv_player dv_unit_get_dv_player( dv_unit unit )
+{
+       if ( unit != NULL )
+       {
+               if ( unit->pump == NULL )
+               {
+                       unit->pump = dv_pump_init( unit->buffer_size );
+                       if ( unit->pump != NULL )
+                               unit->player = dv_player_init( unit->pump );
+               }
+               return unit->player;
+       }
+       return NULL;
+}
+
+
+/** Transfer the currently loaded clip to another unit
+*/
+
+int dv_unit_transfer( dv_unit dest_unit, dv_unit src_unit )
+{
+       dv_player src_player = dv_unit_get_dv_player( src_unit );
+       dv_player dest_player = dv_unit_get_dv_player( dest_unit );
+
+       if( dest_player != NULL && src_player != NULL )
+               dv_player_replace_player( dest_player, src_player );
+
+       return 0;
+}
+
+/** Get the guid associated to this unit.
+*/
+
+octlet_t dv_unit_get_guid( dv_unit unit )
+{
+       return unit->guid;
+}
+
+/** Get the node id associated to this unit.
+*/
+
+int dv_unit_get_nodeid( dv_unit unit )
+{
+       return (unit->node_id & 0x3f);
+}
+
+/** Get the channel associated to this unit.
+*/
+
+int dv_unit_get_channel( dv_unit unit )
+{
+       return (unit->channel);
+}
+
+/** Turn unit online.
+*/
+
+int dv_unit_online( dv_unit unit )
+{
+       int result = 0;
+       int port, node_id;
+       
+       if ( unit->raw1394 != NULL )
+               raw1394_close( unit->raw1394 );
+       
+       node_id = raw1394_find_node( &(unit->raw1394), unit->guid );
+       if ( node_id != -1 )
+       {
+               unit->node_id = 0xffc0 | node_id;       
+               port = dv_unit_get_port( unit );
+       
+               unit->dv1394_fd = open( devices[ port ][ device_count[port] ], O_RDWR );
+               if ( unit->dv1394_fd < 0 )
+               {
+                       dv1394d_log( LOG_ERR, "failed to open dv1394 device - %s\n", devices[ port ][ device_count[port] ] );
+                       dv_unit_close( unit );
+               }
+               else
+               {
+                       device_count[ port ] ++;
+                       if ( establish_p2p_connection( unit->raw1394, unit->node_id, (unsigned int *) &(unit->channel) ) )
+                       {
+                               avc1394_vcr_record( unit->raw1394, unit->node_id );
+                               unit->online = 1;
+                               dv_unit_status_communicate( unit );
+                               result = 1;
+                       }
+               }
+       }
+                               
+       return result;
+}
+
+/** Turn unit offline.
+*/
+
+void dv_unit_offline( dv_unit unit )
+{
+       if ( unit->online == 1 )
+       {
+               if ( unit->is_terminated == 0 )
+                       dv_unit_terminate( unit );
+               unit->online = 0;
+               if ( unit->raw1394 != NULL )
+               {
+                       avc1394_vcr_stop( unit->raw1394, unit->node_id );
+                       break_p2p_connection( unit->raw1394, unit->node_id, unit->channel );
+               }
+               if ( unit->dv1394_fd > -1 )
+               {
+                       close( unit->dv1394_fd );
+                       device_count[ dv_unit_get_port( unit ) ] --;
+               }
+               dv_unit_status_communicate( unit );
+               dv1394d_log( LOG_DEBUG, "Unit with GUID %08x%08x is now offline.",
+                       (quadlet_t) (unit->guid>>32), (quadlet_t) (unit->guid & 0xffffffff) );
+       }
+}
+
+/** Determine if unit is offline.
+*/
+
+int dv_unit_is_offline( dv_unit unit )
+{
+       return (unit->online == 0);
+}
+
+/** Obtain the status for a given unit
+*/
+
+int dv_unit_get_status( dv_unit unit, dv1394_status status )
+{
+       int error = -1;
+
+       memset( status, 0, sizeof( dv1394_status_t ) );
+
+       if ( unit != NULL )
+       {
+               dv_player player = dv_unit_get_dv_player( unit );
+
+               error = 0;
+
+               if ( player != NULL )
+               {
+                       dv_frame head = dv_pump_get_head( player->pump );
+                       dv_frame tail = dv_pump_get_tail( player->pump );
+
+                       status->speed = (int)( dv_player_get_speed( player ) * 1000.0 );
+                       status->fps = dv_player_frames_per_second( player, 0 );
+
+                       if ( head != NULL )
+                       {
+                               dv_frame_id id = dv_frame_get_id( head );
+                               if ( id->resource != NULL )
+                               {
+                                       const char *resource = id->resource;
+                                       if ( resource != NULL && unit->root_dir != NULL )
+                                               resource += strlen( unit->root_dir ) - ( unit->root_dir[ strlen( unit->root_dir ) - 1 ] == '/' );
+                                       strncpy( status->clip, resource, sizeof( status->clip ) );
+                               }
+                               else
+                               {
+                                       char *title = dv_player_get_name( player, dv_player_get_clip_containing( player, 0 ), unit->root_dir );
+                                       if ( title != NULL )
+                                               strncpy( status->clip, title, sizeof( status->clip ) );
+                               }
+
+                               status->position = id->relative;
+                               status->in = id->in;
+                               status->out = id->out;
+                               status->length = id->length;
+                               status->seek_flag = id->seek_flag;
+                       }
+                       else
+                       {
+                               char *title = dv_player_get_name( player, dv_player_get_clip_containing( player, 0 ), unit->root_dir );
+                               if ( title != NULL )
+                                       strncpy( status->clip, title, sizeof( status->clip ) );
+                       }
+
+                       if ( tail != NULL )
+                       {
+                               dv_frame_id id = dv_frame_get_id( tail );
+                               const char *resource = id->resource;
+                               if ( resource != NULL && unit->root_dir != NULL )
+                                       resource += strlen( unit->root_dir ) - ( unit->root_dir[ strlen( unit->root_dir ) - 1 ] == '/' );
+                               if ( resource != NULL )
+                                       strncpy( status->tail_clip, resource, sizeof( status->clip ) );
+                               status->tail_position = id->relative;
+                               status->tail_in = id->in;
+                               status->tail_out = id->out;
+                               status->tail_length = id->length;
+                       }
+                       
+                       status->generation = player->generation;
+                       status->clip_index = dv_unit_get_current_clip( unit );
+               }
+
+               if ( dv_unit_is_offline( unit ) )
+                       status->status = unit_offline;
+               else if ( !strcmp( status->clip, "" ) )
+                       status->status = unit_not_loaded;
+               else if ( dv_unit_has_terminated( unit ) )
+                       status->status = unit_stopped;
+               else if ( status->speed == 0 )
+                       status->status = unit_paused;
+               else
+                       status->status = unit_playing;
+       }
+       else
+       {
+               status->status = unit_undefined;
+       }
+
+       status->unit = unit->unit;
+
+       return error;
+}
+
+/** Change position in the playlist.
+*/
+
+void dv_unit_change_position( dv_unit unit, int clip, long position )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_player_set_clip_position( player, clip, position );
+       dv_unit_status_communicate( unit );
+}
+
+/** Change speed.
+*/
+
+void dv_unit_change_speed( dv_unit unit, int speed )
+{
+       if ( dv_unit_has_terminated( unit ) )
+               dv_unit_change_position( unit, 0, 0 );
+       else
+               dv_unit_play( unit, speed );
+}
+
+int    dv_unit_get_current_clip( dv_unit unit )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       unsigned long position = dv_player_get_position( player );
+       return dv_player_get_clip_containing( player, position );
+}
+
+/** Set a clip's in point
+*/
+
+int dv_unit_set_clip_in( dv_unit unit, int index, long position )
+{
+       int error = 0;
+       dv_player player = dv_unit_get_dv_player( unit );
+
+       if ( player != NULL )
+       {
+               dv_unit_change_speed( unit, 0 );
+               if ( dv_player_set_in_point( player, index, (unsigned long) position ) == position )
+                       dv_player_set_clip_position( player, index, position );
+               else
+                       error = -2;
+       }
+       else
+       {
+               error = -1;
+       }
+
+       dv_unit_status_communicate( unit );
+
+       return error;
+
+}
+
+/** Set a clip's out point.
+*/
+
+int dv_unit_set_clip_out( dv_unit unit, int index, long position )
+{
+       int error = 0;
+       dv_player player = dv_unit_get_dv_player( unit );
+
+       if ( player != NULL )
+       {
+               dv_unit_change_speed( unit, 0 );
+               if ( dv_player_set_out_point( player, index, position ) == position )
+                       dv_player_set_clip_position( player, index, position );
+               else
+                       error = -2;
+       }
+       else
+       {
+               error = -1;
+       }
+
+       dv_unit_status_communicate( unit );
+
+       return error;
+}
+
+/** Step by specified position.
+*/
+
+void dv_unit_step( dv_unit unit, int offset )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_player_change_position( player, dv_seek_relative, offset );
+}
+
+/** Set the unit's clip mode regarding in and out points.
+*/
+
+void dv_unit_set_mode( dv_unit unit, dv_player_clip_mode mode )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       if ( player != NULL )
+               dv_player_set_clip_mode( player, mode );
+       dv_unit_status_communicate( unit );
+}
+
+/** Get the unit's clip mode regarding in and out points.
+*/
+
+dv_player_clip_mode dv_unit_get_mode( dv_unit unit )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       return dv_player_get_clip_mode( player );
+}
+
+/** Set the unit's clip mode regarding eof handling.
+*/
+
+void dv_unit_set_eof_action( dv_unit unit, dv_player_eof_action action )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       dv_player_set_eof_action( player, action );
+       dv_unit_status_communicate( unit );
+}
+
+/** Get the unit's clip mode regarding eof handling.
+*/
+
+dv_player_eof_action dv_unit_get_eof_action( dv_unit unit )
+{
+       dv_player player = dv_unit_get_dv_player( unit );
+       return dv_player_get_eof_action( player );
+}
+
+/** Release the unit
+
+    \todo error handling
+    \param unit A dv_unit handle.
+*/
+
+void dv_unit_close( dv_unit unit )
+{
+       if ( unit != NULL )
+       {
+               dv1394d_log( LOG_DEBUG, "closing unit..." );
+               dv_unit_offline( unit );
+               if ( unit->pump != NULL )
+               {
+                       dv_pump_terminate( unit->pump );
+                       dv_pump_flush( unit->pump );
+                       dv_pump_return_used_output( unit->pump );
+                       dv_input_join_thread( unit->in );
+                       if ( !unit->is_terminated )
+                               pthread_join( unit->out, NULL );
+                       dv_pump_close( unit->pump );
+                       unit->pump = NULL;
+               }
+               raw1394_close( unit->raw1394 );
+               free( unit );
+               dv1394d_log( LOG_DEBUG, "... unit closed." );
+       }
+}
+
+/** Get the raw1394 port associated to this unit.
+*/
+
+int dv_unit_get_port( dv_unit unit )
+{
+       if ( unit->raw1394 != NULL )
+               return (int) raw1394_get_userdata( unit->raw1394 );
+       else
+               return -1;
+}
+
+/** Set the dv1394 file descriptor for the unit.
+*/
+
+void dv_unit_set_dv1394_fd( dv_unit unit, int fd )
+{
+       unit->dv1394_fd = fd;
+}
+
+/** Get the dv1394 syt_offset (timestamp latency) property.
+*/
+
+unsigned int dv_unit_get_syt_offset( dv_unit unit )
+{
+       return unit->dv1394_syt_offset;
+}
+
+/** Get the dv1394 cip_n (timing numerator) property.
+*/
+
+unsigned int dv_unit_get_cip_n( dv_unit unit )
+{
+       return unit->dv1394_cip_n;
+}
+
+/** Get the dv1394 cip_d (timing denominator) property.
+*/
+
+unsigned int dv_unit_get_cip_d( dv_unit unit )
+{
+       return unit->dv1394_cip_d;
+}
+
+/** Set the dv1394 syt_offset (timestamp latency) property.
+
+    Stops and restarts the unit if playing.
+*/
+
+void dv_unit_set_syt_offset( dv_unit unit, unsigned int syt_offset )
+{
+       int restart = !unit->is_terminated;
+       int speed = (int)( dv_player_get_speed( dv_unit_get_dv_player(unit) ) * 1000.0 );
+       
+       dv_unit_terminate( unit );
+       unit->dv1394_syt_offset = syt_offset;
+       if ( restart )
+               dv_unit_play( unit, speed );
+}
+       
+/** Set the dv1394 cip_n (timing numerator) property.
+
+    Stops and restarts the unit if playing.
+*/
+
+void dv_unit_set_cip_n( dv_unit unit, unsigned int cip_n )
+{
+       int restart = !unit->is_terminated;
+       int speed = (int)( dv_player_get_speed( dv_unit_get_dv_player(unit) ) * 1000.0 );
+       
+       dv_unit_terminate( unit );
+       unit->dv1394_cip_n = cip_n;
+       if ( restart )
+               dv_unit_play( unit, speed );
+}
+
+/** Set the dv1394 cip_d (timing denominator) property.
+
+    Stops and restarts the unit if playing.
+*/
+
+void dv_unit_set_cip_d( dv_unit unit, unsigned int cip_d )
+{
+       int restart = !unit->is_terminated;
+       int speed = (int)( dv_player_get_speed( dv_unit_get_dv_player(unit) ) * 1000.0 );
+       
+       dv_unit_terminate( unit );
+       unit->dv1394_cip_d = cip_d;
+       if ( restart )
+               dv_unit_play( unit, speed );
+}
+
+/** Terminate, but only the output thread and close dv1394.
+*/
+
+void dv_unit_suspend( dv_unit unit )
+{
+       if ( unit->is_terminated == 0 )
+       {
+               unit->is_terminated = 1;
+               unit->is_suspended = 1;
+               dv_pump_terminate( unit->pump );
+               dv_pump_flush( unit->pump );
+               pthread_cancel( unit->out );
+       }
+       if ( unit->dv1394_fd > -1 )
+       {
+               close( unit->dv1394_fd );
+               device_count[ dv_unit_get_port( unit ) ] --;
+       }
+       unit->dv1394_fd = -1;
+       dv_unit_status_communicate( unit );
+}
+
+
+/** Restore unit on the bus, re-open dv1394, start playback if pump is running.
+*/
+
+void dv_unit_restore( dv_unit unit )
+{
+       int result = 0;
+       int port, node_id;
+       
+       if ( unit->raw1394 != NULL )
+               raw1394_close( unit->raw1394 );
+       
+       node_id = raw1394_find_node( &(unit->raw1394), unit->guid );
+       if ( node_id != -1 )
+       {
+               unit->node_id = 0xffc0 | node_id;       
+               port = dv_unit_get_port( unit );
+       
+               unit->dv1394_fd = open( devices[ port ][ device_count[port] ], O_RDWR );
+               if ( unit->dv1394_fd < 0 )
+               {
+                       dv1394d_log( LOG_ERR, "failed to open dv1394 device - %s\n", devices[ port ][ device_count[port] ] );
+                       dv_unit_close( unit );
+               }
+               else
+               {
+                       device_count[ port ] ++;
+                       break_p2p_connection( unit->raw1394, unit->node_id, unit->channel );
+                       if ( establish_p2p_connection( unit->raw1394, unit->node_id, (unsigned int *) &(unit->channel) ) )
+                       {
+                               avc1394_vcr_record( unit->raw1394, unit->node_id );
+                               unit->online = 1;
+                               result = 1;
+                       }
+               }
+       }
+       if ( unit->is_suspended == 1 )
+       {
+               int retval;
+               dv_frame frame = dv_pump_get_available_output( unit->pump );
+               struct dv1394_init setup =
+               {
+                       api_version: DV1394_API_VERSION,
+                       channel: unit->channel,
+                       /* this only sets the *requested* size of the ringbuffer,
+                          in frames */ 
+                       n_frames: unit->n_frames,
+                       format: dv_frame_is_pal(frame) ? DV1394_PAL : DV1394_NTSC,
+                       cip_n: unit->dv1394_cip_n,
+                       cip_d: unit->dv1394_cip_d,
+                       syt_offset: unit->dv1394_syt_offset
+               };
+               pthread_attr_t attr;
+
+               dv_input_join_thread( unit->in );
+               unit->is_terminated = 0;
+               unit->is_suspended = 0;
+               dv_pump_restart( unit->pump );
+               dv_input_start_thread( unit->in );
+               
+               /* initialize dv1394 */
+               retval = ioctl( unit->dv1394_fd, DV1394_INIT, &setup );
+               if ( retval < 0 )
+                       return;
+               
+               pthread_attr_init( &attr );
+               pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
+               pthread_attr_setinheritsched( &attr, PTHREAD_INHERIT_SCHED );
+               /* pthread_attr_setschedpolicy( &attr, SCHED_RR ); */
+               pthread_create( &unit->out, &attr, output, unit );
+       }
+       dv_unit_status_communicate( unit );
+}
diff --git a/src/miracle/miracle_unit.h b/src/miracle/miracle_unit.h
new file mode 100644 (file)
index 0000000..5433818
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * dvunit.h -- DV Transmission Unit Header
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DV_UNIT_H_
+#define _DV_UNIT_H_
+
+#include <pthread.h>
+#include <libraw1394/raw1394.h>
+
+#include <dv1394notifier.h>
+#include <dv1394status.h>
+#include <dvpump.h>
+#include <dvplayer.h>
+#include <dvinput.h>
+#include <dverror.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct
+{
+       int        unit;
+       dv_pump    pump;
+       dv_player  player;
+       dv_input   in;
+       int                dv1394_fd;
+       int        is_terminated;
+       int        is_suspended;
+       pthread_t  out;
+       int                channel;
+       nodeid_t   node_id;
+       octlet_t   guid;
+       raw1394handle_t raw1394;
+       int        allow_stdin;
+       int        buffer_size;
+       int        online;
+       dv1394_notifier notifier;
+       char      *root_dir;
+       unsigned int dv1394_syt_offset;
+       unsigned int dv1394_cip_n;
+       unsigned int dv1394_cip_d;
+       unsigned int n_frames;
+       unsigned int n_fill;
+       uint8_t *mmap;
+       int mmap_pos;
+       int mmap_length;
+} dv_unit_t, *dv_unit;
+
+extern dv_unit              dv_unit_init( octlet_t guid, int channel );
+extern void                 dv_unit_allow_stdin( dv_unit unit, int flag );
+extern void                 dv_unit_set_buffer_size( dv_unit unit, int size );
+extern int                  dv_unit_get_buffer_size( dv_unit unit );
+extern void                 dv_unit_set_n_frames( dv_unit unit, int size );
+extern int                                     dv_unit_get_n_frames( dv_unit unit );
+extern void                 dv_unit_set_n_fill( dv_unit unit, int size );
+extern int                                     dv_unit_get_n_fill( dv_unit unit );
+extern dv_error_code        dv_unit_load( dv_unit unit, const char *clip, long in, long out, int flush );
+extern dv_error_code           dv_unit_insert( dv_unit unit, const char *clip, int index, long in, long out );
+extern dv_error_code        dv_unit_append( dv_unit unit, const char *clip, long in, long out );
+extern dv_error_code           dv_unit_remove( dv_unit unit, int index );
+extern dv_error_code           dv_unit_clean( dv_unit unit );
+extern dv_error_code           dv_unit_move( dv_unit unit, int src, int dest );
+extern int                  dv_unit_transfer( dv_unit dest_unit, dv_unit src_unit );
+extern void                 dv_unit_play( dv_unit_t *unit, int speed );
+extern void                 dv_unit_terminate( dv_unit );
+extern int                  dv_unit_has_terminated( dv_unit );
+extern octlet_t             dv_unit_get_guid( dv_unit unit );
+extern int                  dv_unit_get_nodeid( dv_unit unit );
+extern int                  dv_unit_get_channel( dv_unit unit );
+extern int                  dv_unit_online( dv_unit unit );
+extern void                 dv_unit_offline( dv_unit unit );
+extern int                  dv_unit_is_offline( dv_unit unit );
+extern void                 dv_unit_set_notifier( dv_unit, dv1394_notifier, char * );
+extern int                  dv_unit_get_status( dv_unit, dv1394_status );
+extern void                 dv_unit_change_position( dv_unit, int, long position );
+extern void                 dv_unit_change_speed( dv_unit unit, int speed );
+extern int                  dv_unit_set_clip_in( dv_unit unit, int index, long position );
+extern int                  dv_unit_set_clip_out( dv_unit unit, int index, long position );
+extern void                 dv_unit_set_mode( dv_unit unit, dv_player_clip_mode mode );
+extern dv_player_clip_mode  dv_unit_get_mode( dv_unit unit );
+extern void                 dv_unit_set_eof_action( dv_unit unit, dv_player_eof_action mode );
+extern dv_player_eof_action dv_unit_get_eof_action( dv_unit unit );
+extern void                 dv_unit_step( dv_unit unit, int offset );
+extern void                 dv_unit_close( dv_unit unit );
+extern int                  dv_unit_get_port( dv_unit unit );
+extern void                 dv_unit_set_dv1394_fd( dv_unit unit, int fd );
+extern unsigned int         dv_unit_get_syt_offset( dv_unit unit );
+extern unsigned int         dv_unit_get_cip_n( dv_unit unit );
+extern unsigned int         dv_unit_get_cip_d( dv_unit unit );
+extern void                 dv_unit_set_syt_offset( dv_unit unit, unsigned int );
+extern void                 dv_unit_set_cip_n( dv_unit unit, unsigned int );
+extern void                 dv_unit_set_cip_d( dv_unit unit, unsigned int );
+extern void                 dv_unit_suspend( dv_unit );
+extern void                 dv_unit_restore( dv_unit );
+extern dv_player                       dv_unit_get_dv_player( dv_unit );
+extern int                                     dv_unit_get_current_clip( dv_unit );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/miracle/miracle_unit_commands.c b/src/miracle/miracle_unit_commands.c
new file mode 100644 (file)
index 0000000..b12f2c7
--- /dev/null
@@ -0,0 +1,612 @@
+/*
+ * unit_commands.c
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "dvunit.h"
+#include "global_commands.h"
+#include "dverror.h"
+#include "dvframepool.h"
+#include "log.h"
+
+int dv1394d_load( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       char *filename = (char*) cmd_arg->argument;
+       char fullname[1024];
+       int flush = 1;
+
+       if ( filename[0] == '!' )
+       {
+               flush = 0;
+               filename ++;
+       }
+
+       if ( filename[0] == '/' )
+               filename++;
+
+       snprintf( fullname, 1023, "%s%s", cmd_arg->root_dir, filename );
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               long in = -1, out = -1;
+               if ( dv_tokeniser_count( cmd_arg->tokeniser ) == 5 )
+               {
+                       in = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 3 ) );
+                       out = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 4 ) );
+               }
+               if ( dv_unit_load( unit, fullname, in, out, flush ) != dv_pump_ok )
+                       return RESPONSE_BAD_FILE;
+       }
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_list( command_argument cmd_arg )
+{
+       int i = 0;
+       dv_unit unit = dv1394d_get_unit( cmd_arg->unit );
+       dv_player player = dv_unit_get_dv_player( unit );
+       
+       if ( player != NULL )
+       {
+               dv_response_printf( cmd_arg->response, 1024, "%d\n", player->generation );
+               
+               for ( i = 0; i < dv_player_get_clip_count( player ); i ++ )
+               {
+                       dv_clip clip = dv_player_get_clip( player, i );
+                       
+                       dv_response_printf( cmd_arg->response, 10240,
+                                                               "%d \"%s\" %d %d %d %d %.2f\n", 
+                                                               i,
+                                                               dv_clip_get_resource( clip, cmd_arg->root_dir ),
+                                                               dv_clip_get_in( clip ),
+                                                               ( !dv_clip_is_seekable( clip ) && clip->out_frame == -1 ? -1 : dv_clip_get_out( clip ) ),
+                                                               dv_clip_get_max_frames( clip ),
+                                                               ( !dv_clip_is_seekable( clip ) && clip->out_frame == -1 ? -1 : dv_player_get_length_of_clip( player, i ) ),
+                                                               dv_clip_frames_per_second( clip ) );
+               }
+       
+               dv_response_printf( cmd_arg->response, 2, "\n" );
+               
+               return RESPONSE_SUCCESS;
+       }
+       return RESPONSE_INVALID_UNIT;
+}
+
+static int parse_clip( command_argument cmd_arg, int arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       int clip = dv_unit_get_current_clip( unit );
+       
+       if ( dv_tokeniser_count( cmd_arg->tokeniser ) > arg )
+       {
+               dv_player player = dv_unit_get_dv_player( unit );
+               char *token = dv_tokeniser_get_string( cmd_arg->tokeniser, arg );
+               if ( token[ 0 ] == '+' )
+                       clip += atoi( token + 1 );
+               else if ( token[ 0 ] == '-' )
+                       clip -= atoi( token + 1 );
+               else
+                       clip = atoi( token );
+               if ( clip < 0 )
+                       clip = 0;
+               if ( clip >= player->size )
+                       clip = player->size - 1;
+       }
+       
+       return clip;
+}
+
+int dv1394d_insert( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       char *filename = (char*) cmd_arg->argument;
+       char fullname[1024];
+
+       if ( filename[0] == '/' )
+               filename++;
+
+       snprintf( fullname, 1023, "%s%s", cmd_arg->root_dir, filename );
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               long in = -1, out = -1;
+               int index = parse_clip( cmd_arg, 3 );
+               
+               if ( dv_tokeniser_count( cmd_arg->tokeniser ) == 6 )
+               {
+                       in = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 4 ) );
+                       out = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 5 ) );
+               }
+               
+               switch( dv_unit_insert( unit, fullname, index, in, out ) )
+               {
+                       case dv_pump_ok:
+                               return RESPONSE_SUCCESS;
+                       case dv_pump_too_many_files_open:
+                               return RESPONSE_TOO_MANY_FILES;
+                       default:
+                               return RESPONSE_BAD_FILE;
+               }
+       }
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_remove( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               int index = parse_clip( cmd_arg, 2 );
+                       
+               if ( dv_unit_remove( unit, index ) != dv_pump_ok )
+                       return RESPONSE_BAD_FILE;
+       }
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_clean( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               if ( dv_unit_clean( unit ) != dv_pump_ok )
+                       return RESPONSE_BAD_FILE;
+       }
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_move( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if ( unit != NULL )
+       {
+               if ( dv_tokeniser_count( cmd_arg->tokeniser ) > 2 )
+               {
+                       int src = parse_clip( cmd_arg, 2 );
+                       int dest = parse_clip( cmd_arg, 3 );
+                       
+                       if ( dv_unit_move( unit, src, dest ) != dv_pump_ok )
+                               return RESPONSE_BAD_FILE;
+               }
+               else
+               {
+                       return RESPONSE_MISSING_ARG;
+               }
+       }
+       else
+       {
+               return RESPONSE_INVALID_UNIT;
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_append( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       char *filename = (char*) cmd_arg->argument;
+       char fullname[1024];
+
+       if ( filename[0] == '/' )
+               filename++;
+       snprintf( fullname, 1023, "%s%s", cmd_arg->root_dir, filename );
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               long in = -1, out = -1;
+               if ( dv_tokeniser_count( cmd_arg->tokeniser ) == 5 )
+               {
+                       in = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 3 ) );
+                       out = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 4 ) );
+               }
+               switch ( dv_unit_append( unit, fullname, in, out ) )
+               {
+                       case dv_pump_ok:
+                               return RESPONSE_SUCCESS;
+                       case dv_pump_too_many_files_open:
+                               return RESPONSE_TOO_MANY_FILES;
+                       default:
+                               return RESPONSE_BAD_FILE;
+               }
+       }
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_play( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               int speed = 1000;
+               if ( dv_tokeniser_count( cmd_arg->tokeniser ) == 3 )
+                       speed = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 2 ) );
+               dv_unit_play( unit, speed );
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_stop( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+               dv_unit_terminate( unit );
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_pause( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else 
+               dv_unit_play( unit, 0 );
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_rewind( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+               dv_unit_change_speed( unit, -2000 );
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_step( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               dv_unit_play( unit, 0 );
+               dv_unit_step( unit, *(int*) cmd_arg->argument );
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_goto( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       int clip = parse_clip( cmd_arg, 3 );
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+               dv_unit_change_position( unit, clip, *(int*) cmd_arg->argument );
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_ff( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+               dv_unit_change_speed( unit, 2000 );
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_set_in_point( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       int clip = parse_clip( cmd_arg, 3 );
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               int position = *(int *) cmd_arg->argument;
+
+               switch( dv_unit_set_clip_in( unit, clip, position ) )
+               {
+                       case -1:
+                               return RESPONSE_BAD_FILE;
+                       case -2:
+                               return RESPONSE_OUT_OF_RANGE;
+               }
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_set_out_point( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       int clip = parse_clip( cmd_arg, 3 );
+       
+       if (unit == NULL || dv_unit_is_offline(unit))
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               int position = *(int *) cmd_arg->argument;
+
+               switch( dv_unit_set_clip_out( unit, clip, position ) )
+               {
+                       case -1:
+                               return RESPONSE_BAD_FILE;
+                       case -2:
+                               return RESPONSE_OUT_OF_RANGE;
+               }
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_get_unit_status( command_argument cmd_arg )
+{
+       dv1394_status_t status;
+       int error = dv_unit_get_status( dv1394d_get_unit( cmd_arg->unit ), &status );
+
+       if ( error == -1 )
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               char text[ 10240 ];
+
+               dv_response_printf( cmd_arg->response, 
+                                                       sizeof( text ), 
+                                                       dv1394_status_serialise( &status, text, sizeof( text ) ) );
+
+               return RESPONSE_SUCCESS_1;
+       }
+       
+       return 0;
+}
+
+
+int dv1394d_set_unit_property( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               char *key = (char*) cmd_arg->argument;
+               char *value = NULL;
+
+               value = strchr( key, '=' );
+               if (value == NULL)
+                       return RESPONSE_OUT_OF_RANGE;
+               value[0] = 0;
+               value++;
+               dv1394d_log( LOG_DEBUG, "USET %s = %s", key, value );
+               if ( strncasecmp( key, "eof", 1024) == 0 )
+               {
+                       if ( strncasecmp( value, "pause", 1024) == 0)
+                               dv_unit_set_eof_action( unit, dv_player_pause );
+                       else if ( strncasecmp( value, "loop", 1024) == 0)
+                               dv_unit_set_eof_action( unit, dv_player_loop );
+                       else if ( strncasecmp( value, "stop", 1024) == 0)
+                               dv_unit_set_eof_action( unit, dv_player_terminate );
+                       else if ( strncasecmp( value, "clean", 1024) == 0)
+                               dv_unit_set_eof_action( unit, dv_player_clean_loop );
+                       else
+                               return RESPONSE_OUT_OF_RANGE;
+               }
+               else if ( strncasecmp( key, "points", 1024) == 0 )
+               {
+                       if ( strncasecmp( value, "use", 1024) == 0)
+                               dv_unit_set_mode( unit, dv_clip_mode_restricted );
+                       else if ( strncasecmp( value, "ignore", 1024) == 0)
+                               dv_unit_set_mode( unit, dv_clip_mode_unrestricted );
+                       else
+                               return RESPONSE_OUT_OF_RANGE;
+               }
+               else if ( strncasecmp( key, "syt_offset", 1024) == 0 )
+               {
+                       dv_unit_set_syt_offset( unit, atoi( value ) );
+               }
+               else if ( strncasecmp( key, "cip_n", 1024) == 0 )
+               {
+                       dv_unit_set_cip_n( unit, atoi( value ) );
+               }
+               else if ( strncasecmp( key, "cip_d", 1024) == 0 )
+               {
+                       dv_unit_set_cip_d( unit, atoi( value ) );
+               }
+               else if ( strncasecmp( key, "size", 1024) == 0 )
+               {
+                       dv_unit_set_buffer_size( unit, atoi( value ) );
+               }
+               else if ( strncasecmp( key, "n_frames", 1024) == 0 )
+               {
+                       dv_unit_set_n_frames( unit, atoi( value ) );
+               }               
+               else if ( strncasecmp( key, "n_fill", 1024) == 0 )
+               {
+                       dv_unit_set_n_fill( unit, atoi( value ) );
+               }               
+               else
+                       return RESPONSE_OUT_OF_RANGE;
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+int dv1394d_get_unit_property( command_argument cmd_arg )
+{
+       dv_unit unit = dv1394d_get_unit(cmd_arg->unit);
+       
+       if (unit == NULL)
+               return RESPONSE_INVALID_UNIT;
+       else
+       {
+               char *key = (char*) cmd_arg->argument;
+
+               if ( strncasecmp( key, "eof", 1024) == 0 )
+               {
+                       switch ( dv_unit_get_eof_action( unit ) )
+                       {
+                               case dv_player_pause:
+                                       dv_response_write( cmd_arg->response, "pause", strlen("pause") );
+                                       break;
+                               case dv_player_loop:
+                                       dv_response_write( cmd_arg->response, "loop", strlen("loop") );
+                                       break;
+                               case dv_player_terminate:
+                                       dv_response_write( cmd_arg->response, "stop", strlen("stop") );
+                                       break;
+                               case dv_player_clean_loop:
+                                       dv_response_write( cmd_arg->response, "clean", strlen("clean") );
+                                       break;
+                       }
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "points", 1024) == 0 )
+               {
+                       if ( dv_unit_get_mode( unit ) == dv_clip_mode_restricted )
+                               dv_response_write( cmd_arg->response, "use", strlen("use") );
+                       else
+                               dv_response_write( cmd_arg->response, "ignore", strlen("ignore") );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "syt_offset", 1024) == 0 )
+               {
+                       dv_response_printf( cmd_arg->response, 1024, "%d\n",
+                               dv_unit_get_syt_offset( unit ) );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "cip_n", 1024) == 0 )
+               {
+                       dv_response_printf( cmd_arg->response, 1024, "%d\n",
+                               dv_unit_get_cip_n( unit ) );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "cip_d", 1024) == 0 )
+               {
+                       dv_response_printf( cmd_arg->response, 1024, "%d\n",
+                               dv_unit_get_cip_d( unit ) );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "size", 1024) == 0 )
+               {
+                       dv_response_printf( cmd_arg->response, 1024, "%d\n",
+                               dv_unit_get_buffer_size( unit ) );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "n_frames", 1024) == 0 )
+               {
+                       dv_response_printf( cmd_arg->response, 1024, "%d\n",
+                               dv_unit_get_n_frames( unit ) );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "n_fill", 1024) == 0 )
+               {
+                       dv_response_printf( cmd_arg->response, 1024, "%d\n",
+                               dv_unit_get_n_fill( unit ) );
+                       return RESPONSE_SUCCESS_1;
+               }
+               else if ( strncasecmp( key, "all", 1024 ) == 0 )
+               {
+                       switch ( dv_unit_get_eof_action( unit ) )
+                       {
+                               case dv_player_pause:
+                                       dv_response_write( cmd_arg->response, "eof=pause\n", strlen("pause") );
+                                       break;
+                               case dv_player_loop:
+                                       dv_response_write( cmd_arg->response, "eof=loop\n", strlen("loop") );
+                                       break;
+                               case dv_player_terminate:
+                                       dv_response_write( cmd_arg->response, "eof=stop\n", strlen("stop") );
+                                       break;
+                               case dv_player_clean_loop:
+                                       dv_response_write( cmd_arg->response, "eof=clean\n", strlen("clean") );
+                                       break;
+                       }
+                       if ( dv_unit_get_mode( unit ) == dv_clip_mode_restricted )
+                               dv_response_write( cmd_arg->response, "points=use\n", strlen("use") );
+                       else
+                               dv_response_write( cmd_arg->response, "points=ignore\n", strlen("ignore") );
+                       dv_response_printf( cmd_arg->response, 1024, "syt_offset=%d\n", dv_unit_get_syt_offset( unit ) );
+                       dv_response_printf( cmd_arg->response, 1024, "cip_n=%d\n", dv_unit_get_cip_n( unit ) );
+                       dv_response_printf( cmd_arg->response, 1024, "cip_d=%d\n", dv_unit_get_cip_d( unit ) );
+                       dv_response_printf( cmd_arg->response, 1024, "size=%d\n", dv_unit_get_buffer_size( unit ) );
+                       dv_response_printf( cmd_arg->response, 1024, "n_frames=%d\n", dv_unit_get_n_frames( unit ) );
+                       dv_response_printf( cmd_arg->response, 1024, "n_fill=%d\n", dv_unit_get_n_fill( unit ) );
+               }
+       }
+       
+       return RESPONSE_SUCCESS;
+}
+
+
+int dv1394d_transfer( command_argument cmd_arg )
+{
+       dv_unit src_unit = dv1394d_get_unit(cmd_arg->unit);
+       int dest_unit_id = -1;
+       char *string = (char*) cmd_arg->argument;
+       if ( string != NULL && ( string[ 0 ] == 'U' || string[ 0 ] == 'u' ) && strlen( string ) > 1 )
+               dest_unit_id = atoi( string + 1 );
+       
+       if ( src_unit != NULL && dest_unit_id != -1 )
+       {
+               dv_unit dest_unit = dv1394d_get_unit( dest_unit_id );
+               if ( dest_unit != NULL && !dv_unit_is_offline(dest_unit) && dest_unit != src_unit )
+               {
+                       dv_unit_transfer( dest_unit, src_unit );
+                       return RESPONSE_SUCCESS;
+               }
+       }
+       
+       return RESPONSE_INVALID_UNIT;
+}
diff --git a/src/miracle/miracle_unit_commands.h b/src/miracle/miracle_unit_commands.h
new file mode 100644 (file)
index 0000000..a7163bd
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * unit_commands.h
+ * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef _UNIT_COMMANDS_H_
+#define _UNIT_COMMANDS_H_
+
+#include "dvconnection.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+extern response_codes dv1394d_list( command_argument );
+extern response_codes dv1394d_load( command_argument );
+extern response_codes dv1394d_insert( command_argument );
+extern response_codes dv1394d_remove( command_argument );
+extern response_codes dv1394d_clean( command_argument );
+extern response_codes dv1394d_move( command_argument );
+extern response_codes dv1394d_append( command_argument );
+extern response_codes dv1394d_play( command_argument );
+extern response_codes dv1394d_stop( command_argument );
+extern response_codes dv1394d_pause( command_argument );
+extern response_codes dv1394d_rewind( command_argument );
+extern response_codes dv1394d_step( command_argument );
+extern response_codes dv1394d_goto( command_argument );
+extern response_codes dv1394d_ff( command_argument );
+extern response_codes dv1394d_set_in_point( command_argument );
+extern response_codes dv1394d_set_out_point( command_argument );
+extern response_codes dv1394d_get_unit_status( command_argument );
+extern response_codes dv1394d_set_unit_property( command_argument );
+extern response_codes dv1394d_get_unit_property( command_argument );
+extern response_codes dv1394d_transfer( command_argument );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/modules/Makefile b/src/modules/Makefile
new file mode 100644 (file)
index 0000000..0a4c717
--- /dev/null
@@ -0,0 +1,15 @@
+SUBDIRS = core gtk2 dv sdl # bluefish mcmpeg
+
+all clean depend install:
+       list='$(SUBDIRS)'; \
+       for subdir in $$list; do \
+               [ ! -f disable-$$subdir ] && $(MAKE) -C $$subdir $@; \
+       done
+
+dist-clean:
+       rm -f consumers.dat filters.dat producers.dat transitions.dat; \
+       list='$(SUBDIRS)'; \
+       for subdir in $$list; do \
+               [ ! -f disable-$$subdir ] && $(MAKE) -C $$subdir $@; \
+       done
+
diff --git a/src/modules/configure b/src/modules/configure
new file mode 100755 (executable)
index 0000000..365fe43
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Clean up disables if not in help mode
+[ "$help" != "1" ] && rm -f disable-* producers.dat filters.dat transitions.dat consumers.dat
+
+# Iterate through arguments
+for i in $*
+do
+       case $i in
+               --disable-* )   touch disable-${i#--disable-} ;;
+       esac
+done
+
+# Iterate through each of the components
+for i in *
+do
+       if [ -x $i/configure -a \( "$help" = "1" -o ! -f disable-$i \) ]
+       then
+               echo "Configuring $i:"
+               pushd $i > /dev/null
+               ./configure $@
+               [ $? != 0 ] && exit 1
+               popd > /dev/null
+       fi
+done
+
diff --git a/src/modules/dv/Makefile b/src/modules/dv/Makefile
new file mode 100644 (file)
index 0000000..22d999e
--- /dev/null
@@ -0,0 +1,29 @@
+
+TARGET = factory.o \
+                libmltdv.so
+
+OBJS = producer_libdv.o 
+
+CFLAGS=-I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread
+
+LDFLAGS=-ldv -lpthread
+
+SRCS := $(OBJS:.o=.c)
+
+all:   $(TARGET)
+
+$(TARGET): $(OBJS)
+               $(CC) -shared -o $@ $(OBJS) $(LDFLAGS)
+
+depend:        $(SRCS)
+               $(CC) -MM $(CFLAGS) $^ 1>.depend
+
+dist-clean:    clean
+               rm -f .depend
+
+clean: 
+               rm -f $(OBJS) $(TARGET)
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/src/modules/dv/configure b/src/modules/dv/configure
new file mode 100755 (executable)
index 0000000..876897c
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+if [ "$help" != "1" ]
+then
+
+cat << EOF >> ../producers.dat
+libdv                  libmltdv.so
+EOF
+
+fi
+
diff --git a/src/modules/dv/factory.c b/src/modules/dv/factory.c
new file mode 100644 (file)
index 0000000..e27510a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * factory.c -- the factory method interfaces
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "producer_libdv.h"
+
+void *mlt_create_producer( char *id, void *arg )
+{
+       if ( !strcmp( id, "libdv" ) )
+               return producer_libdv_init( arg );
+       return NULL;
+}
+
+void *mlt_create_filter( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_transition( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_consumer( char *id, void *arg )
+{
+       return NULL;
+}
+
diff --git a/src/modules/dv/producer_libdv.c b/src/modules/dv/producer_libdv.c
new file mode 100644 (file)
index 0000000..5d2c768
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * producer_libdv.c -- simple libdv test case
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "producer_libdv.h"
+#include <framework/mlt_frame.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <libdv/dv.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+typedef struct producer_libdv_s *producer_libdv;
+
+struct producer_libdv_s
+{
+       struct mlt_producer_s parent;
+       int fd;
+       dv_decoder_t *dv_decoder;
+       int is_pal;
+       uint64_t file_size;
+       int frame_size;
+       long frames_in_file;
+};
+
+static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index );
+static void producer_close( mlt_producer parent );
+
+static int producer_collect_info( producer_libdv this );
+
+mlt_producer producer_libdv_init( char *filename )
+{
+       producer_libdv this = calloc( sizeof( struct producer_libdv_s ), 1 );
+
+       if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 )
+       {
+               mlt_producer producer = &this->parent;
+
+               // Register transport implementation with the producer
+               producer->close = producer_close;
+
+               // Register our get_frame implementation with the producer
+               producer->get_frame = producer_get_frame;
+
+               // Create the dv_decoder
+               this->dv_decoder = dv_decoder_new( FALSE, FALSE, FALSE );
+               this->dv_decoder->quality = DV_QUALITY_BEST;
+               this->dv_decoder->audio->arg_audio_emphasis = 2;
+               dv_set_audio_correction( this->dv_decoder, DV_AUDIO_CORRECT_AVERAGE );
+
+               // Open the file if specified
+               if ( filename != NULL )
+               {
+                       this->fd = open( filename, O_RDONLY );
+                       producer_collect_info( this );
+               }
+
+               // Return the producer
+               return producer;
+       }
+       free( this );
+       return NULL;
+}
+
+static int read_frame( int fd, uint8_t* frame_buf, int *isPAL )
+{
+       int result = read( fd, frame_buf, frame_size_525_60 ) == frame_size_525_60;
+       if ( result )
+       {
+               *isPAL = ( frame_buf[3] & 0x80 );
+
+               if ( *isPAL )
+               {
+                       int diff = frame_size_625_50 - frame_size_525_60;
+                       result = read( fd, frame_buf + frame_size_525_60, diff ) == diff;
+               }
+       }
+       
+       return result;
+}
+
+static int producer_collect_info( producer_libdv this )
+{
+       int valid = 0;
+       uint8_t *dv_data = malloc( frame_size_625_50 );
+
+       if ( dv_data != NULL )
+       {
+               // Read the first frame
+               valid = read_frame( this->fd, dv_data, &this->is_pal );
+
+               // If it looks like a valid frame, the get stats
+               if ( valid )
+               {
+                       // Get the properties
+                       mlt_properties properties = mlt_producer_properties( &this->parent );
+
+                       // Determine the file size
+                       struct stat buf;
+                       fstat( this->fd, &buf );
+
+                       // Store the file size
+                       this->file_size = buf.st_size;
+
+                       // Determine the frame size
+                       this->frame_size = this->is_pal ? frame_size_625_50 : frame_size_525_60;
+
+                       // Determine the number of frames in the file
+                       this->frames_in_file = this->file_size / this->frame_size;
+
+                       // Calculate default in/out points
+                       double fps = this->is_pal ? 25 : 30000 / 1001;
+                       mlt_timecode length = ( mlt_timecode )( this->frames_in_file ) / fps;
+                       mlt_properties_set_double( properties, "fps", fps );
+                       mlt_properties_set_timecode( properties, "playtime", length );
+                       mlt_properties_set_timecode( properties, "length", length );
+                       mlt_properties_set_timecode( properties, "in", 0.0 );
+                       mlt_properties_set_timecode( properties, "out", length );
+
+                       // Set the speed to normal
+                       mlt_properties_set_double( properties, "speed", 1 );
+               }
+
+               free( dv_data );
+       }
+
+       return valid;
+}
+
+#if 0
+static int mc_producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
+{
+       // Get the frames properties
+       mlt_properties properties = mlt_frame_properties( this );
+
+       // Get the dv data
+       uint8_t *dv_data = mlt_properties_get_data( properties, "dv_data", NULL );
+
+       // Determine bytes in frame
+       int bytes_in_frame = dv_data[ 3 ] & 0x80 ? frame_size_625_50 : frame_size_525_60;
+
+       // Assign width and height from properties
+       *width = mlt_properties_get_int( properties, "width" );
+       *height = mlt_properties_get_int( properties, "height" );
+
+       if ( *format == mlt_image_yuv422 )
+       {
+               // Allocate image
+               *buffer = malloc( *width * *height * 2 );
+
+               // Decompress
+               DecompressBuffer_DV( dv_data, bytes_in_frame, *buffer, *width * 2, *width, *height, 0, FOURCC_YUYV, 0, NULL );
+
+               // Set the image on the properties
+               mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, free, NULL );
+       }
+       else
+       {
+               // Allocate image
+               *buffer = malloc( *width * *height * 3 );
+
+               // Decompress
+               DecompressBuffer_DV( dv_data, bytes_in_frame, *buffer, *width * 3, *width, *height, 0, FOURCC_R24C, 0, NULL );
+
+               // Set the image on the properties
+               mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, free, NULL );
+       }
+
+       return 0;
+}
+#endif
+
+static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
+{
+       int pitches[3] = { 0, 0, 0 };
+       uint8_t *pixels[3] = { NULL, NULL, NULL };
+       
+       // Get the frames properties
+       mlt_properties properties = mlt_frame_properties( this );
+
+       // Get the dv decoder
+       dv_decoder_t *decoder = mlt_properties_get_data( properties, "dv_decoder", NULL );
+
+       // Get the dv data
+       uint8_t *dv_data = mlt_properties_get_data( properties, "dv_data", NULL );
+
+       // Assign width and height from properties
+       *width = mlt_properties_get_int( properties, "width" );
+       *height = mlt_properties_get_int( properties, "height" );
+
+       // Parse the header
+       dv_parse_header( decoder, dv_data );
+
+       // Extract an image of the format requested
+       if ( *format == mlt_image_yuv422 )
+       {
+               // Allocate an image
+               uint8_t *image = malloc( *width * *height * 2 );
+
+               // Pass to properties for clean up
+               mlt_properties_set_data( properties, "image", image, *width * *height * 2, free, NULL );
+
+               // Decode the image
+               pitches[ 0 ] = *width * 2;
+               pixels[ 0 ] = image;
+               dv_decode_full_frame( decoder, dv_data, e_dv_color_yuv, pixels, pitches );
+
+               // Assign result
+               *buffer = image;
+       }
+       else if ( *format == mlt_image_rgb24 )
+       {
+               // Allocate an image
+               uint8_t *image = malloc( *width * *height * 3 );
+
+               // Pass to properties for clean up
+               mlt_properties_set_data( properties, "image", image, *width * *height * 3, free, NULL );
+
+               // Decode the frame
+               pitches[ 0 ] = 720 * 3;
+               pixels[ 0 ] = image;
+               dv_decode_full_frame( decoder, dv_data, e_dv_color_rgb, pixels, pitches );
+
+               // Assign result
+               *buffer = image;
+       }
+
+       return 0;
+}
+
+static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
+{
+       int16_t *p;
+       int i, j;
+       int16_t *audio_channels[ 4 ];
+       
+       // Get the frames properties
+       mlt_properties properties = mlt_frame_properties( this );
+
+       // Get the dv decoder
+       dv_decoder_t *decoder = mlt_properties_get_data( properties, "dv_decoder", NULL );
+
+       // Get the dv data
+       uint8_t *dv_data = mlt_properties_get_data( properties, "dv_data", NULL );
+
+       // Parse the header for meta info
+       dv_parse_header( decoder, dv_data );
+
+       // Obtain required values
+       *frequency = decoder->audio->frequency;
+       *samples = decoder->audio->samples_this_frame;
+       *channels = decoder->audio->num_channels;
+
+       // Create a temporary workspace
+       for ( i = 0; i < 4; i++ )
+               audio_channels[ i ] = malloc( DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ) );
+
+       // Create a workspace for the result
+       *buffer = malloc( *channels * DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ) );
+
+       // Pass the allocated audio buffer as a property
+       mlt_properties_set_data( properties, "audio", *buffer, *channels * DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ), free, NULL );
+
+       // Decode the audio
+       dv_decode_full_audio( decoder, dv_data, audio_channels );
+       
+       // Interleave the audio
+       p = *buffer;
+       for ( i = 0; i < *samples; i++ )
+               for ( j = 0; j < *channels; j++ )
+                       *p++ = audio_channels[ j ][ i ];
+
+       // Free the temporary work space
+       for ( i = 0; i < 4; i++ )
+               free( audio_channels[ i ] );
+
+       return 0;
+}
+
+static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
+{
+       producer_libdv this = producer->child;
+       uint8_t *data = malloc( frame_size_625_50 );
+       
+       // Obtain the current frame number
+       uint64_t position = mlt_producer_frame( producer );
+       
+       // Convert timecode to a file position (ensuring that we're on a frame boundary)
+       uint64_t offset = position * this->frame_size;
+
+       // Create an empty frame
+       *frame = mlt_frame_init( );
+
+       // Seek and fetch
+       if ( this->fd != 0 && 
+                lseek( this->fd, offset, SEEK_SET ) == offset &&
+                read_frame( this->fd, data, &this->is_pal ) )
+       {
+               // Get the frames properties
+               mlt_properties properties = mlt_frame_properties( *frame );
+
+               // Pass the dv decoder
+               mlt_properties_set_data( properties, "dv_decoder", this->dv_decoder, 0, NULL, NULL );
+
+               // Pass the dv data
+               mlt_properties_set_data( properties, "dv_data", data, frame_size_625_50, free, NULL );
+
+               // Update other info on the frame
+               mlt_properties_set_int( properties, "width", 720 );
+               mlt_properties_set_int( properties, "height", this->is_pal ? 576 : 480 );
+
+               // Hmm - register audio callback
+               ( *frame )->get_audio = producer_get_audio;
+               
+               // Push the get_image method on to the stack
+               mlt_frame_push_get_image( *frame, producer_get_image );
+       }
+       else
+       {
+               free( data );
+       }
+
+       // Update timecode on the frame we're creating
+       mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) );
+
+       // Calculate the next timecode
+       mlt_producer_prepare_next( producer );
+
+       return 0;
+}
+
+static void producer_close( mlt_producer parent )
+{
+       // Obtain this
+       producer_libdv this = parent->child;
+
+       // Free the dv deconder
+       dv_decoder_free( this->dv_decoder );
+
+       // Close the file
+       if ( this->fd != 0 )
+               close( this->fd );
+
+       // Close the parent
+       parent->close = NULL;
+       mlt_producer_close( parent );
+
+       // Free the memory
+       free( this );
+}
+
diff --git a/src/modules/dv/producer_libdv.h b/src/modules/dv/producer_libdv.h
new file mode 100644 (file)
index 0000000..c493eae
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * producer_libdv.h -- a DV decoder based on libdv
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _PRODUCER_LIBDV_H_
+#define _PRODUCER_LIBDV_H_
+
+#include <framework/mlt_producer.h>
+
+extern mlt_producer producer_libdv_init( char *filename );
+
+#endif
diff --git a/src/modules/gtk2/Makefile b/src/modules/gtk2/Makefile
new file mode 100644 (file)
index 0000000..0136b31
--- /dev/null
@@ -0,0 +1,29 @@
+
+TARGET = libmltgtk2.so
+
+OBJS = factory.o \
+          producer_pixbuf.o 
+
+CFLAGS=`pkg-config gdk-pixbuf-2.0 --cflags` -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread
+
+LDFLAGS=`pkg-config gdk-pixbuf-2.0 --libs`
+
+SRCS := $(OBJS:.o=.c)
+
+all:   $(TARGET)
+
+$(TARGET): $(OBJS)
+               $(CC) -shared -o $@ $(OBJS) $(LDFLAGS)
+
+depend:        $(SRCS)
+               $(CC) -MM $(CFLAGS) $^ 1>.depend
+
+dist-clean:    clean
+               rm -f .depend
+
+clean: 
+               rm -f $(OBJS) $(TARGET)
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/src/modules/gtk2/configure b/src/modules/gtk2/configure
new file mode 100755 (executable)
index 0000000..2112336
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+if [ "$help" != "1" ]
+then
+
+cat << EOF >> ../producers.dat
+pixbuf                 libmltgtk2.so
+EOF
+
+fi
+
diff --git a/src/modules/gtk2/factory.c b/src/modules/gtk2/factory.c
new file mode 100644 (file)
index 0000000..fc3a7fa
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * factory.c -- the factory method interfaces
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "producer_pixbuf.h"
+
+void *mlt_create_producer( char *id, void *arg )
+{
+       if ( !strcmp( id, "pixbuf" ) )
+               return producer_pixbuf_init( arg );
+       return NULL;
+}
+
+void *mlt_create_filter( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_transition( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_consumer( char *id, void *arg )
+{
+       return NULL;
+}
+
diff --git a/src/modules/gtk2/producer_pixbuf.c b/src/modules/gtk2/producer_pixbuf.c
new file mode 100644 (file)
index 0000000..8a74a46
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * producer_pixbuf.c -- raster image loader based upon gdk-pixbuf
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "producer_pixbuf.h"
+#include <framework/mlt_frame.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index );
+static void producer_close( mlt_producer parent );
+
+mlt_producer producer_pixbuf_init( const char *filename )
+{
+       producer_pixbuf this = calloc( sizeof( struct producer_pixbuf_s ), 1 );
+       if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 )
+       {
+               mlt_producer producer = &this->parent;
+
+               producer->get_frame = producer_get_frame;
+               producer->close = producer_close;
+
+               this->filename = strdup( filename );
+               this->counter = -1;
+               g_type_init();
+
+               return producer;
+       }
+       free( this );
+       return NULL;
+}
+
+static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
+{
+       // Obtain properties of frame
+       mlt_properties properties = mlt_frame_properties( this );
+
+       // May need to know the size of the image to clone it
+       int size = 0;
+
+       // Get the image
+       uint8_t *image = mlt_properties_get_data( properties, "image", &size );
+
+       // Get width and height
+       *width = mlt_properties_get_int( properties, "width" );
+       *height = mlt_properties_get_int( properties, "height" );
+
+       // Clone if necessary
+       if ( writable )
+       {
+               // Clone our image
+               uint8_t *copy = malloc( size );
+               memcpy( copy, image, size );
+
+               // We're going to pass the copy on
+               image = copy;
+
+               // Now update properties so we free the copy after
+               mlt_properties_set_data( properties, "image", copy, size, free, NULL );
+       }
+
+       // Pass on the image
+       *buffer = image;
+
+       return 0;
+}
+
+uint8_t *producer_get_alpha_mask( mlt_frame this )
+{
+       // Obtain properties of frame
+       mlt_properties properties = mlt_frame_properties( this );
+
+       // Return the alpha mask
+       return mlt_properties_get_data( properties, "alpha", NULL );
+}
+
+static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
+{
+       producer_pixbuf this = producer->child;
+       GdkPixbuf *pixbuf = NULL;
+       GError *error = NULL;
+
+       // Generate a frame
+       *frame = mlt_frame_init( );
+
+       // Obtain properties of frame
+       mlt_properties properties = mlt_frame_properties( *frame );
+
+    // optimization for subsequent iterations on single picture
+       if ( this->image != NULL )
+       {
+               // Set width/height
+               mlt_properties_set_int( properties, "width", this->width );
+               mlt_properties_set_int( properties, "height", this->height );
+
+               // if picture sequence pass the image and alpha data without destructor
+               mlt_properties_set_data( properties, "image", this->image, 0, NULL, NULL );
+               mlt_properties_set_data( properties, "alpha", this->alpha, 0, NULL, NULL );
+
+               // Set alpha mask call back
+        ( *frame )->get_alpha_mask = producer_get_alpha_mask;
+
+               // Stack the get image callback
+               mlt_frame_push_get_image( *frame, producer_get_image );
+
+       }
+       else if ( strchr( this->filename, '%' ) != NULL )
+       {
+               // handle picture sequences
+               char filename[1024];
+               filename[1023] = 0;
+               int current = this->counter;
+               do
+               {
+                       ++this->counter;
+                       snprintf( filename, 1023, this->filename, this->counter );
+                       pixbuf = gdk_pixbuf_new_from_file( filename, &error );
+                       // allow discontinuity in frame numbers up to 99
+                       error = NULL;
+               } while ( pixbuf == NULL && ( this->counter - current ) < 100 );
+       }
+       else
+       {
+               pixbuf = gdk_pixbuf_new_from_file( this->filename, &error );
+       }
+
+       // If we have a pixbuf
+       if ( pixbuf )
+       {
+               // Store width and height
+               this->width = gdk_pixbuf_get_width( pixbuf );
+               this->height = gdk_pixbuf_get_height( pixbuf );
+
+               // Allocate/define image and alpha
+               uint8_t *image = malloc( this->width * this->height * 2 );
+               uint8_t *alpha = NULL;
+
+               // Extract YUV422 and alpha
+               if ( gdk_pixbuf_get_has_alpha( pixbuf ) )
+               {
+                       // Allocate the alpha mask
+                       alpha = malloc( this->width * this->height );
+
+                       // Convert the image
+                       mlt_convert_rgb24a_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ),
+                                                                                 this->width, this->height,
+                                                                                 gdk_pixbuf_get_rowstride( pixbuf ),
+                                                                                 image, alpha );
+               }
+               else
+               { 
+                       // No alpha to extract
+                       mlt_convert_rgb24_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ),
+                                                                                this->width, this->height,
+                                                                                gdk_pixbuf_get_rowstride( pixbuf ),
+                                                                                image );
+               }
+
+               // Finished with pixbuf now
+               g_object_unref( pixbuf );
+
+               // Set width/height of frame
+               mlt_properties_set_int( properties, "width", this->width );
+               mlt_properties_set_int( properties, "height", this->height );
+
+               // Pass alpha and image on properties with or without destructor
+               if ( this->counter >= 0 )
+               {
+                       // if picture sequence pass the image and alpha data with destructor
+                       mlt_properties_set_data( properties, "image", image, 0, free, NULL );
+                       mlt_properties_set_data( properties, "alpha", alpha, 0, free, NULL );
+               }
+               else
+               {
+                       // if single picture, reference the image and alpha in the producer
+                       this->image = image;
+                       this->alpha = alpha;
+
+                       // pass the image and alpha data without destructor
+                       mlt_properties_set_data( properties, "image", image, 0, NULL, NULL );
+                       mlt_properties_set_data( properties, "alpha", alpha, 0, NULL, NULL );
+               }
+
+               // Set alpha call back
+               ( *frame )->get_alpha_mask = producer_get_alpha_mask;
+
+               // Push the get_image method
+               mlt_frame_push_get_image( *frame, producer_get_image );
+       }
+
+       // Update timecode on the frame we're creating
+       mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) );
+
+       // Calculate the next timecode
+       mlt_producer_prepare_next( producer );
+
+       return 0;
+}
+
+static void producer_close( mlt_producer parent )
+{
+       producer_pixbuf this = parent->child;
+       if ( this->filename )
+               free( this->filename );
+       if ( this->image )
+               free( this->image );
+       if ( this->alpha )
+               free( this->alpha );
+       parent->close = NULL;
+       mlt_producer_close( parent );
+       free( this );
+}
+
diff --git a/src/modules/gtk2/producer_pixbuf.h b/src/modules/gtk2/producer_pixbuf.h
new file mode 100644 (file)
index 0000000..c7f76ef
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * producer_pixbuf.h -- raster image loader based upon gdk-pixbuf
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _PRODUCER_PIXBUF_H_
+#define _PRODUCER_PIXBUF_H_
+
+#include <framework/mlt_producer.h>
+
+typedef struct producer_pixbuf_s *producer_pixbuf;
+
+struct producer_pixbuf_s
+{
+       struct mlt_producer_s parent;
+       char *filename;
+       int counter;
+       int width;
+       int height;
+       uint8_t *image;
+       uint8_t *alpha;
+};
+
+extern mlt_producer producer_pixbuf_init( const char *filename );
+
+#endif
diff --git a/src/modules/sdl/Makefile b/src/modules/sdl/Makefile
new file mode 100644 (file)
index 0000000..5107441
--- /dev/null
@@ -0,0 +1,29 @@
+
+TARGET = libmltsdl.so
+
+OBJS = factory.o \
+          consumer_sdl.o 
+
+CFLAGS=-I../../ `sdl-config --cflags` -Wall -g -D_FILE_OFFSET_BITS=64 -pthread
+
+LDFLAGS= `sdl-config --libs`
+
+SRCS := $(OBJS:.o=.c)
+
+all:   $(TARGET)
+
+$(TARGET): $(OBJS)
+               $(CC) -shared -o $@ $(OBJS) $(LDFLAGS)
+
+depend:        $(SRCS)
+               $(CC) -MM $(CFLAGS) $^ 1>.depend
+
+dist-clean:    clean
+               rm -f .depend
+
+clean: 
+               rm -f $(OBJS) $(TARGET)
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/src/modules/sdl/configure b/src/modules/sdl/configure
new file mode 100755 (executable)
index 0000000..1c40fac
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+if [ "$help" != "1" ]
+then
+
+cat << EOF >> ../consumers.dat
+sdl                            libmltsdl.so
+EOF
+
+fi
+
diff --git a/src/modules/sdl/consumer_sdl.c b/src/modules/sdl/consumer_sdl.c
new file mode 100644 (file)
index 0000000..59196d2
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * consumer_sdl.c -- A Simple DirectMedia Layer consumer
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "consumer_sdl.h"
+#include <framework/mlt_frame.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <SDL/SDL.h>
+#include <SDL/SDL_syswm.h>
+
+/** This classes definition.
+*/
+
+typedef struct consumer_sdl_s *consumer_sdl;
+
+struct consumer_sdl_s
+{
+       struct mlt_consumer_s parent;
+       mlt_properties properties;
+       int format;
+       int video;
+       pthread_t thread;
+       int running;
+       uint8_t audio_buffer[ 4096 * 6 ];
+       int audio_avail;
+       pthread_mutex_t audio_mutex;
+       pthread_cond_t audio_cond;
+       int window_width;
+       int window_height;
+};
+
+/** Forward references to static functions.
+*/
+
+static void consumer_close( mlt_consumer parent );
+static void *consumer_thread( void * );
+static void consumer_get_dimensions( int *width, int *height );
+
+/** This is what will be called by the factory - anything can be passed in
+       via the argument, but keep it simple.
+*/
+
+mlt_consumer consumer_sdl_init( void *dummy )
+{
+       // Create the consumer object
+       consumer_sdl this = calloc( sizeof( struct consumer_sdl_s ), 1 );
+
+       // If no malloc'd and consumer init ok
+       if ( this != NULL && mlt_consumer_init( &this->parent, this ) == 0 )
+       {
+               // Get the parent consumer object
+               mlt_consumer parent = &this->parent;
+
+               // We have stuff to clean up, so override the close method
+               parent->close = consumer_close;
+
+               // get a handle on properties
+               mlt_service service = mlt_consumer_service( parent );
+               this->properties = mlt_service_properties( service );
+
+               // Set the default volume
+               mlt_properties_set_double( this->properties, "volume", 1.0 );
+
+               // This is the initialisation of the consumer
+               this->running = 1;
+               pthread_mutex_init( &this->audio_mutex, NULL );
+               pthread_cond_init( &this->audio_cond, NULL);
+               
+               // TODO: process actual param
+               
+               // Create the the thread
+               pthread_create( &this->thread, NULL, consumer_thread, this );
+
+               // Return the consumer produced
+               return parent;
+       }
+
+       // malloc or consumer init failed
+       free( this );
+
+       // Indicate failure
+       return NULL;
+}
+
+static int sdl_lock_display( )
+{
+       SDL_Surface *screen = SDL_GetVideoSurface( );
+       return screen != NULL && ( !SDL_MUSTLOCK( screen ) || SDL_LockSurface( screen ) >= 0 );
+}
+
+static void sdl_unlock_display( )
+{
+       SDL_Surface *screen = SDL_GetVideoSurface( );
+       if ( screen != NULL && SDL_MUSTLOCK( screen ) )
+               SDL_UnlockSurface( screen );
+}
+
+void sdl_fill_audio( void *udata, Uint8 *stream, int len )
+{
+       consumer_sdl this = udata;
+
+       // Get the volume
+       float volume = mlt_properties_get_double( this->properties, "volume" );
+
+       pthread_mutex_lock( &this->audio_mutex );
+
+       // Experimental - block until audio received
+       while ( this->running && len > this->audio_avail )
+               pthread_cond_wait( &this->audio_cond, &this->audio_mutex );
+
+       if ( this->audio_avail >= len )
+       {
+               // Place in the audio buffer
+               SDL_MixAudio( stream, this->audio_buffer, len, ( int )( ( float )SDL_MIX_MAXVOLUME * volume ) );
+
+               // Remove len from the audio available
+               this->audio_avail -= len;
+
+               // Remove the samples
+               memmove( this->audio_buffer, this->audio_buffer + len, this->audio_avail );
+       }
+       else
+       {
+               // Just to be safe, wipe the stream first
+               memset( stream, 0, len );
+
+               // Copy what we have into the stream
+               memcpy( stream, this->audio_buffer, this->audio_avail );
+
+               // Mix the audio 
+               SDL_MixAudio( stream, stream, len, ( int )( ( float )SDL_MIX_MAXVOLUME * volume ) );
+
+               // No audio left
+               this->audio_avail = 0;
+       }
+       pthread_cond_broadcast( &this->audio_cond );
+       pthread_mutex_unlock( &this->audio_mutex );
+}
+
+/** Threaded wrapper for pipe.
+*/
+
+static void *consumer_thread( void *arg )
+{
+       // Identify the arg
+       consumer_sdl this = arg;
+
+       // Get the consumer
+       mlt_consumer consumer = &this->parent;
+
+       // Get the service assoicated to the consumer
+       mlt_service service = mlt_consumer_service( consumer );
+
+       // Define a frame pointer
+       mlt_frame frame;
+
+       // internal intialization
+       int sdl_flags = SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_HWACCEL | SDL_RESIZABLE;
+       SDL_Surface *sdl_screen = NULL;
+       SDL_Overlay *sdl_overlay = NULL;
+       uint8_t *buffer = NULL;
+       int init_audio = 1;
+       int bytes;
+
+       if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ) < 0 )
+       {
+               fprintf( stderr, "Failed to initialize SDL: %s\n", SDL_GetError() );
+               return NULL;
+       }
+       
+       // Loop until told not to
+       while( this->running )
+       {
+               // Get a frame from the service (should never return anything other than 0)
+               if ( mlt_service_get_frame( service, &frame, 0 ) == 0 )
+               {
+                       mlt_image_format vfmt = mlt_image_yuv422;
+                       int width, height;
+                       uint8_t *image;
+
+                       mlt_audio_format afmt = mlt_audio_pcm;
+                       int channels;
+                       int samples;
+                       int frequency;
+                       int16_t *pcm;
+
+                       mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples );
+                       if ( init_audio == 1 )
+                       {
+                               SDL_AudioSpec request;
+
+                               // specify audio format
+                               request.freq = frequency;
+                               request.format = AUDIO_S16;
+                               request.channels = channels;
+                               request.samples = 1024;
+                               request.callback = sdl_fill_audio;
+                               request.userdata = (void *)this;
+                               if ( SDL_OpenAudio( &request, NULL ) < 0 )
+                               {
+                                       fprintf( stderr, "SDL failed to open audio: %s\n", SDL_GetError() );
+                                       break;
+                               }
+                               SDL_PauseAudio( 0 );
+                               init_audio = 0;
+                       }
+                       bytes = ( samples * channels * 2 );
+                       pthread_mutex_lock( &this->audio_mutex );
+                       while ( bytes > ( sizeof( this->audio_buffer) - this->audio_avail ) )
+                               pthread_cond_wait( &this->audio_cond, &this->audio_mutex );
+                       memcpy( &this->audio_buffer[ this->audio_avail ], pcm, bytes );
+                       this->audio_avail += bytes;
+                       pthread_cond_broadcast( &this->audio_cond );
+                       pthread_mutex_unlock( &this->audio_mutex );
+
+                       // Get the image, width and height
+                       mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 );
+                       if ( width != this->window_width || height != this->window_height )
+                       {
+                               SDL_Rect rect;
+                               this->window_width = rect.w = width;
+                               this->window_height = rect.h = height;
+
+                               // open SDL window with video overlay, if possible
+                               if ( sdl_screen == NULL )
+                                       sdl_screen = SDL_SetVideoMode( width, height, 0, sdl_flags );
+                               if ( sdl_screen != NULL )
+                               {
+                                       rect.x = rect.y = 0;
+
+
+                                       // XXX: this is a little hack until we have some sort of aspect
+                                       // ratio property on images.
+                                       if ( rect.h <= 486 )
+                                       {
+                                               rect.w = 640;
+                                               rect.x = ( 720 - 640 ) / 2;
+                                       }
+                                       else
+                                       {
+                                               rect.h = 540;
+                                               rect.y = ( 576 - 540 ) / 2;
+                                       }
+
+                                       SDL_SetClipRect( sdl_screen, &rect );
+                                       
+                                       // Force an overlay recreation
+                                       if ( sdl_overlay != NULL )
+                                               SDL_FreeYUVOverlay( sdl_overlay );
+                                       sdl_lock_display();
+                                       sdl_overlay = SDL_CreateYUVOverlay( width, height, SDL_YUY2_OVERLAY, sdl_screen );
+                                       sdl_unlock_display();
+                               }
+                       }
+                       
+                       if ( sdl_screen != NULL && sdl_overlay != NULL )
+                       {
+                               buffer = sdl_overlay->pixels[ 0 ];
+                               if ( sdl_lock_display() )
+                               {
+                                       if ( SDL_LockYUVOverlay( sdl_overlay ) >= 0 )
+                                       {
+                                               memcpy( buffer, image, width * height * 2 );
+                                               SDL_UnlockYUVOverlay( sdl_overlay );
+                                               SDL_DisplayYUVOverlay( sdl_overlay, &sdl_screen->clip_rect );
+                                       }
+                                       sdl_unlock_display();
+                               }
+                       }
+                       else
+                       {
+                               // TODO: allocate buffer?
+                       }
+
+                       // Close the frame
+                       mlt_frame_close( frame );
+               }
+               else
+               {
+                       break;
+               }
+       } // while
+
+       // internal cleanup
+       if ( init_audio == 0 )
+               SDL_AudioQuit( );
+       if ( sdl_overlay != NULL )
+               SDL_FreeYUVOverlay( sdl_overlay );
+       SDL_Quit( );
+
+       return NULL;
+}
+
+static void consumer_get_dimensions( int *width, int *height )
+{
+       // SDL windows manager structure
+       SDL_SysWMinfo wm;
+
+       // Specify the SDL Version
+       SDL_VERSION( &wm.version );
+
+       // Get the wm structure
+       if ( SDL_GetWMInfo( &wm ) == 1 )
+       {
+               // Check that we have the X11 wm
+               if ( wm.subsystem == SDL_SYSWM_X11 ) 
+               {
+                       // Get the SDL window
+                       Window window = wm.info.x11.window;
+
+                       // Get the display session
+                       Display *display = wm.info.x11.display;
+
+                       // Get the window attributes
+                       XWindowAttributes attr;
+                       XGetWindowAttributes( display, window, &attr );
+
+                       // Return width and height
+                       *width = attr.width;
+                       *height = attr.height;
+               }
+       }
+}
+
+/** Callback to allow override of the close method.
+*/
+
+static void consumer_close( mlt_consumer parent )
+{
+       // Get the actual object
+       consumer_sdl this = parent->child;
+
+       // Kill the thread and clean up
+       this->running = 0;
+       pthread_join( this->thread, NULL );
+
+       pthread_mutex_destroy( &this->audio_mutex );
+       pthread_cond_destroy( &this->audio_cond );
+               
+       // Now clean up the rest (the close = NULL is a bit nasty but needed for now)
+       parent->close = NULL;
+       mlt_consumer_close( parent );
+
+       // Finally clean up this
+       free( this );
+}
+
diff --git a/src/modules/sdl/consumer_sdl.h b/src/modules/sdl/consumer_sdl.h
new file mode 100644 (file)
index 0000000..6c8114e
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * consumer_sdl.h -- A Simple DirectMedia Layer consumer
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CONSUMER_SDL_H_
+#define _CONSUMER_SDL_H_
+
+#include <framework/mlt_consumer.h>
+
+extern mlt_consumer consumer_sdl_init( void * );
+
+#endif
diff --git a/src/modules/sdl/factory.c b/src/modules/sdl/factory.c
new file mode 100644 (file)
index 0000000..9e5f56e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * factory.c -- the factory method interfaces
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "consumer_sdl.h"
+
+void *mlt_create_producer( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_filter( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_transition( char *id, void *arg )
+{
+       return NULL;
+}
+
+void *mlt_create_consumer( char *id, void *arg )
+{
+       if ( !strcmp( id, "sdl" ) )
+               return consumer_sdl_init( arg );
+       return NULL;
+}
+
diff --git a/src/tests/charlie.c b/src/tests/charlie.c
new file mode 100644 (file)
index 0000000..174cb20
--- /dev/null
@@ -0,0 +1,79 @@
+#include "mlt_producer.h"
+#include "mlt_consumer.h"
+#include "mlt_filter.h"
+#include "mlt_tractor.h"
+#include "mlt_transition.h"
+#include "mlt_multitrack.h"
+
+#include "producer_libdv.h"
+#include "producer_ppm.h"
+#include "filter_deinterlace.h"
+#include "filter_greyscale.h"
+#include "consumer_sdl.h"
+
+#include <stdio.h>
+
+int main( int argc, char **argv )
+{
+       char temp[ 132 ];
+       char *file1 = NULL;
+       char *file2 = NULL;
+
+       // Start the consumer...
+       mlt_consumer sdl_out = consumer_sdl_init( NULL );
+
+       fprintf( stderr, "Press return to continue\n" );
+       fgets( temp, 132, stdin );
+
+       if ( argc >= 2 )
+               file1 = argv[ 1 ];
+       if ( argc >= 3 )
+               file2 = argv[ 2 ];
+
+       // Create the producer(s)
+       //mlt_producer dv1 = producer_ppm_init( NULL );
+       //mlt_producer dv2 = producer_ppm_init( NULL );
+       mlt_producer dv1 = producer_libdv_init( file1 );
+       mlt_producer dv2 = producer_libdv_init( file2 );
+
+       mlt_consumer_connect( sdl_out, mlt_producer_service( dv1 ) );
+
+       fprintf( stderr, "Press return to continue\n" );
+       fgets( temp, 132, stdin );
+
+       // Register producers(s) with a multitrack object
+       mlt_multitrack multitrack = mlt_multitrack_init( );
+       mlt_multitrack_connect( multitrack, dv1, 0 );
+       mlt_multitrack_connect( multitrack, dv2, 1 );
+
+       // Create a filter and associate it to track 0
+       mlt_filter filter = filter_deinterlace_init( NULL );
+       mlt_filter_connect( filter, mlt_multitrack_service( multitrack ), 0 );
+       mlt_filter_set_in_and_out( filter, 0, 5 );
+
+       // Create another
+       mlt_filter greyscale = filter_greyscale_init( NULL );
+       mlt_filter_connect( greyscale, mlt_filter_service( filter ), 0 );
+       mlt_filter_set_in_and_out( greyscale, 0, 10 );
+
+       // Buy a tractor and connect it to the filter
+       mlt_tractor tractor = mlt_tractor_init( );
+       mlt_tractor_connect( tractor, mlt_filter_service( greyscale ) );
+
+       // Connect the tractor to the consumer
+       mlt_consumer_connect( sdl_out, mlt_tractor_service( tractor ) );
+
+       // Do stuff until we're told otherwise...
+       fprintf( stderr, "Press return to continue\n" );
+       fgets( temp, 132, stdin );
+
+       // Close everything...
+       mlt_consumer_close( sdl_out );
+       mlt_tractor_close( tractor );
+       mlt_filter_close( filter );
+       mlt_multitrack_close( multitrack );
+       mlt_producer_close( dv1 );
+       mlt_producer_close( dv2 );
+
+       return 0;
+}
diff --git a/src/tests/dan.c b/src/tests/dan.c
new file mode 100644 (file)
index 0000000..ee76bb0
--- /dev/null
@@ -0,0 +1,72 @@
+#include "mlt_producer.h"
+#include "mlt_consumer.h"
+#include "mlt_filter.h"
+#include "mlt_tractor.h"
+#include "mlt_transition.h"
+#include "mlt_multitrack.h"
+
+#include "producer_libdv.h"
+#include "filter_deinterlace.h"
+#include "consumer_sdl.h"
+#include "producer_ppm.h"
+#include "producer_pixbuf.h"
+#include "transition_composite.h"
+
+#include <stdio.h>
+
+int main( int argc, char **argv )
+{
+       char temp[ 132 ];
+       char *file1 = NULL;
+       char *file2 = NULL;
+
+       if ( argc >= 2 )
+               file1 = argv[ 1 ];
+       if ( argc >= 3 )
+               file2 = argv[ 2 ];
+
+       // Start the consumer...
+       mlt_consumer sdl_out = consumer_sdl_init( NULL );
+
+       // Create the producer(s)
+       mlt_producer dv1 = producer_libdv_init( file1 );
+       //mlt_producer dv1 = producer_pixbuf_init( file1 );
+       //mlt_producer dv2 = producer_libdv_init( file2 );
+       mlt_producer dv2 = producer_pixbuf_init( file2 );
+
+       // Register producers(s) with a multitrack object
+       mlt_multitrack multitrack = mlt_multitrack_init( );
+       mlt_multitrack_connect( multitrack, dv1, 0 );
+       mlt_multitrack_connect( multitrack, dv2, 1 );
+
+       // Create a filter and associate it to track 0
+       mlt_filter filter = filter_deinterlace_init( NULL );
+       mlt_filter_connect( filter, mlt_multitrack_service( multitrack ), 0 );
+       mlt_filter_set_in_and_out( filter, 0, 1000 );
+
+       // Define a transition
+       mlt_transition transition = transition_composite_init( NULL );
+       mlt_transition_connect( transition, mlt_filter_service( filter ), 0, 1 );
+       mlt_transition_set_in_and_out( transition, 0, 1000 );
+
+       // Buy a tractor and connect it to the filter
+       mlt_tractor tractor = mlt_tractor_init( );
+       mlt_tractor_connect( tractor, mlt_transition_service( transition ) );
+
+       // Connect the tractor to the consumer
+       mlt_consumer_connect( sdl_out, mlt_tractor_service( tractor ) );
+
+       // Do stuff until we're told otherwise...
+       fprintf( stderr, "Press return to continue\n" );
+       fgets( temp, 132, stdin );
+
+       // Close everything...
+       mlt_consumer_close( sdl_out );
+       mlt_tractor_close( tractor );
+       mlt_filter_close( filter );
+       mlt_multitrack_close( multitrack );
+       mlt_producer_close( dv1 );
+       mlt_producer_close( dv2 );
+
+       return 0;
+}
diff --git a/src/tests/test.png b/src/tests/test.png
new file mode 100644 (file)
index 0000000..b3fca64
Binary files /dev/null and b/src/tests/test.png differ
diff --git a/src/valerie/Makefile b/src/valerie/Makefile
new file mode 100644 (file)
index 0000000..908c432
--- /dev/null
@@ -0,0 +1,37 @@
+
+AR = ar
+
+OBJS = valerie.o \
+          valerie_notifier.o \
+          valerie_parser.o \
+          valerie_response.o \
+          valerie_status.o \
+          valerie_tokeniser.o \
+          valerie_util.o \
+          valerie_remote.o \
+          valerie_socket.o
+
+SRCS := $(OBJS:.o=.c)
+
+CFLAGS=-Wall -g -D_FILE_OFFSET_BITS=64 -pthread
+
+LDFLAGS=-ldv -lpthread
+
+all: libvalerie.a
+
+libvalerie.a: $(OBJS)
+       $(AR) rvu $@ $(OBJS)
+       ranlib $@
+
+depend:        $(SRCS)
+               $(CC) -MM $(CFLAGS) $^ 1>.depend
+
+dist-clean:    clean
+               rm -f .depend
+
+clean: 
+               rm -f $(OBJS) libvalerie.a 
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/src/valerie/configure b/src/valerie/configure
new file mode 100755 (executable)
index 0000000..1a24852
--- /dev/null
@@ -0,0 +1 @@
+#!/bin/sh
diff --git a/src/valerie/valerie.c b/src/valerie/valerie.c
new file mode 100644 (file)
index 0000000..2e1f289
--- /dev/null
@@ -0,0 +1,875 @@
+/*
+ * valerie.c -- High Level Client API for miracle
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+/* Application header files */
+#include "valerie.h"
+#include "valerie_tokeniser.h"
+#include "valerie_util.h"
+
+/** Initialise the valerie structure.
+*/
+
+valerie valerie_init( valerie_parser parser )
+{
+       valerie this = malloc( sizeof( valerie_t ) );
+       if ( this != NULL )
+       {
+               memset( this, 0, sizeof( valerie_t ) );
+               this->parser = parser;
+       }
+       return this;
+}
+
+/** Set the response structure associated to the last command.
+*/
+
+static void valerie_set_last_response( valerie this, valerie_response response )
+{
+       if ( this != NULL )
+       {
+               if ( this->last_response != NULL )
+                       valerie_response_close( this->last_response );
+               this->last_response = response;
+       }
+}
+
+/** Connect to the parser.
+*/
+
+valerie_error_code valerie_connect( valerie this )
+{
+       valerie_error_code error = valerie_server_unavailable;
+       valerie_response response = valerie_parser_connect( this->parser );
+       if ( response != NULL )
+       {
+               valerie_set_last_response( this, response );
+               if ( valerie_response_get_error_code( response ) == 100 )
+                       error = valerie_ok;
+       }
+       return error;
+}
+
+/** Interpret a non-context sensitive error code.
+*/
+
+static valerie_error_code valerie_get_error_code( valerie this, valerie_response response )
+{
+       valerie_error_code error = valerie_server_unavailable;
+       switch( valerie_response_get_error_code( response ) )
+       {
+               case -1:
+                       error = valerie_server_unavailable;
+                       break;
+               case -2:
+                       error = valerie_no_response;
+                       break;
+               case 200:
+               case 201:
+               case 202:
+                       error = valerie_ok;
+                       break;
+               case 400:
+                       error = valerie_invalid_command;
+                       break;
+               case 401:
+                       error = valerie_server_timeout;
+                       break;
+               case 402:
+                       error = valerie_missing_argument;
+                       break;
+               case 403:
+                       error = valerie_unit_unavailable;
+                       break;
+               case 404:
+                       error = valerie_invalid_file;
+                       break;
+               default:
+               case 500:
+                       error = valerie_unknown_error;
+                       break;
+       }
+       return error;
+}
+
+/** Execute a command.
+*/
+
+valerie_error_code valerie_execute( valerie this, size_t size, char *format, ... )
+{
+       valerie_error_code error = valerie_server_unavailable;
+       char *command = malloc( size );
+       if ( this != NULL && command != NULL )
+       {
+               va_list list;
+               va_start( list, format );
+               if ( vsnprintf( command, size, format, list ) != 0 )
+               {
+                       valerie_response response = valerie_parser_execute( this->parser, command );
+                       valerie_set_last_response( this, response );
+                       error = valerie_get_error_code( this, response );
+               }
+               else
+               {
+                       error = valerie_invalid_command;
+               }
+               va_end( list );
+       }
+       else
+       {
+               error = valerie_malloc_failed;
+       }
+       free( command );
+       return error;
+}
+
+/** Set a global property.
+*/
+
+valerie_error_code valerie_set( valerie this, char *property, char *value )
+{
+       return valerie_execute( this, 1024, "SET %s=%s", property, value );
+}
+
+/** Get a global property.
+*/
+
+valerie_error_code valerie_get( valerie this, char *property, char *value, int length )
+{
+       valerie_error_code error = valerie_execute( this, 1024, "GET %s", property );
+       if ( error == valerie_ok )
+       {
+               valerie_response response = valerie_get_last_response( this );
+               strncpy( value, valerie_response_get_line( response, 1 ), length );
+       }
+       return error;
+}
+
+/** Run a script.
+*/
+
+valerie_error_code valerie_run( valerie this, char *file )
+{
+       return valerie_execute( this, 10240, "RUN \"%s\"", file );
+}
+
+/** Add a unit.
+*/
+
+valerie_error_code valerie_unit_add( valerie this, char *guid, int *unit )
+{
+       valerie_error_code error = valerie_execute( this, 1024, "UADD %s", guid );
+       if ( error == valerie_ok )
+       {
+               int length = valerie_response_count( this->last_response );
+               char *line = valerie_response_get_line( this->last_response, length - 2 );
+               if ( line == NULL || sscanf( line, "U%d", unit ) != 1 )
+                       error = valerie_unit_creation_failed;
+       }
+       else
+       {
+               if ( error == valerie_unknown_error )
+                       error = valerie_unit_creation_failed;
+       }
+       return error;
+}
+
+/** Load a file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_load( valerie this, int unit, char *file )
+{
+       return valerie_execute( this, 10240, "LOAD U%d \"%s\"", unit, file );
+}
+
+static void valerie_interpret_clip_offset( char *output, valerie_clip_offset offset, int clip )
+{
+       switch( offset )
+       {
+               case valerie_absolute:
+                       sprintf( output, "%d", clip );
+                       break;
+               case valerie_relative:
+                       if ( clip < 0 )
+                               sprintf( output, "%d", clip );
+                       else
+                               sprintf( output, "+%d", clip );
+                       break;
+       }
+}
+
+/** Load a file on the specified unit with the specified in/out points.
+*/
+
+valerie_error_code valerie_unit_load_clipped( valerie this, int unit, char *file, double in, double out )
+{
+       return valerie_execute( this, 10240, "LOAD U%d \"%s\" %e %e", unit, file, in, out );
+}
+
+/** Load a file on the specified unit at the end of the current pump.
+*/
+
+valerie_error_code valerie_unit_load_back( valerie this, int unit, char *file )
+{
+       return valerie_execute( this, 10240, "LOAD U%d \"!%s\"", unit, file );
+}
+
+/** Load a file on the specified unit at the end of the pump with the specified in/out points.
+*/
+
+valerie_error_code valerie_unit_load_back_clipped( valerie this, int unit, char *file, double in, double out )
+{
+       return valerie_execute( this, 10240, "LOAD U%d \"!%s\" %e %e", unit, file, in, out );
+}
+
+/** Append a file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_append( valerie this, int unit, char *file, double in, double out )
+{
+       return valerie_execute( this, 10240, "APND U%d \"%s\" %e %e", unit, file, in, out );
+}
+
+/** Clean the unit - this function removes all but the currently playing clip.
+*/
+
+valerie_error_code valerie_unit_clean( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "CLEAN U%d", unit );
+}
+
+/** Move clips on the units playlist.
+*/
+
+valerie_error_code valerie_unit_clip_move( valerie this, int unit, valerie_clip_offset src_offset, int src, valerie_clip_offset dest_offset, int dest )
+{
+       char temp1[ 100 ];
+       char temp2[ 100 ];
+       valerie_interpret_clip_offset( temp1, src_offset, src );
+       valerie_interpret_clip_offset( temp2, dest_offset, dest );
+       return valerie_execute( this, 1024, "MOVE U%d %s %s", unit, temp1, temp2 );
+}
+
+/** Remove clip at the specified position.
+*/
+
+valerie_error_code valerie_unit_clip_remove( valerie this, int unit, valerie_clip_offset offset, int clip )
+{
+       char temp[ 100 ];
+       valerie_interpret_clip_offset( temp, offset, clip );
+       return valerie_execute( this, 1024, "REMOVE U%d %s", unit, temp );
+}
+
+/** Remove the currently playing clip.
+*/
+
+valerie_error_code valerie_unit_remove_current_clip( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "REMOVE U%d", unit );
+}
+
+/** Insert clip at the specified position.
+*/
+
+valerie_error_code valerie_unit_clip_insert( valerie this, int unit, valerie_clip_offset offset, int clip, char *file, double in, double out )
+{
+       char temp[ 100 ];
+       valerie_interpret_clip_offset( temp, offset, clip );
+       return valerie_execute( this, 1024, "INSERT U%d %s %s %e %e", unit, file, temp, in, out );
+}
+
+/** Play the unit at normal speed.
+*/
+
+valerie_error_code valerie_unit_play( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "PLAY U%d 1000", unit );
+}
+
+/** Play the unit at specified speed.
+*/
+
+valerie_error_code valerie_unit_play_at_speed( valerie this, int unit, double speed )
+{
+       return valerie_execute( this, 10240, "PLAY U%d %e", unit, speed );
+}
+
+/** Stop playback on the specified unit.
+*/
+
+valerie_error_code valerie_unit_stop( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "STOP U%d", unit );
+}
+
+/** Pause playback on the specified unit.
+*/
+
+valerie_error_code valerie_unit_pause( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "PAUSE U%d", unit );
+}
+
+/** Rewind the specified unit.
+*/
+
+valerie_error_code valerie_unit_rewind( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "REW U%d", unit );
+}
+
+/** Fast forward the specified unit.
+*/
+
+valerie_error_code valerie_unit_fast_forward( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "FF U%d", unit );
+}
+
+/** Step by the number of frames on the specified unit.
+*/
+
+valerie_error_code valerie_unit_step( valerie this, int unit, double step )
+{
+       return valerie_execute( this, 1024, "STEP U%d %e", unit, step );
+}
+
+/** Goto the specified frame on the specified unit.
+*/
+
+valerie_error_code valerie_unit_goto( valerie this, int unit, double position )
+{
+       return valerie_execute( this, 1024, "GOTO U%d %e", unit, position );
+}
+
+/** Goto the specified frame in the clip on the specified unit.
+*/
+
+valerie_error_code valerie_unit_clip_goto( valerie this, int unit, valerie_clip_offset offset, int clip, double position )
+{
+       char temp[ 100 ];
+       valerie_interpret_clip_offset( temp, offset, clip );
+       return valerie_execute( this, 1024, "GOTO U%d %e %s", unit, position, temp );
+}
+
+/** Set the in point of the loaded file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_set_in( valerie this, int unit, double in )
+{
+       return valerie_execute( this, 1024, "SIN U%d %e", unit, in );
+}
+
+/** Set the in point of the clip on the specified unit.
+*/
+
+valerie_error_code valerie_unit_clip_set_in( valerie this, int unit, valerie_clip_offset offset, int clip, double in )
+{
+       char temp[ 100 ];
+       valerie_interpret_clip_offset( temp, offset, clip );
+       return valerie_execute( this, 1024, "SIN U%d %e %s", unit, in, temp );
+}
+
+/** Set the out point of the loaded file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_set_out( valerie this, int unit, double out )
+{
+       return valerie_execute( this, 1024, "SOUT U%d %e", unit, out );
+}
+
+/** Set the out point of the clip on the specified unit.
+*/
+
+valerie_error_code valerie_unit_clip_set_out( valerie this, int unit, valerie_clip_offset offset, int clip, double in )
+{
+       char temp[ 100 ];
+       valerie_interpret_clip_offset( temp, offset, clip );
+       return valerie_execute( this, 1024, "SOUT U%d %e %s", unit, in, temp );
+}
+
+/** Clear the in point of the loaded file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_clear_in( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "SIN U%d -1", unit );
+}
+
+/** Clear the out point of the loaded file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_clear_out( valerie this, int unit )
+{
+       return valerie_execute( this, 1024, "SOUT U%d -1", unit );
+}
+
+/** Clear the in and out points on the loaded file on the specified unit.
+*/
+
+valerie_error_code valerie_unit_clear_in_out( valerie this, int unit )
+{
+       valerie_error_code error = valerie_unit_clear_out( this, unit );
+       if ( error == valerie_ok )
+               error = valerie_unit_clear_in( this, unit );
+       return error;
+}
+
+/** Set a unit configuration property.
+*/
+
+valerie_error_code valerie_unit_set( valerie this, int unit, char *name, char *value )
+{
+       return valerie_execute( this, 1024, "USET U%d %s=%s", unit, name, value );
+}
+
+/** Get a unit configuration property.
+*/
+
+valerie_error_code valerie_unit_get( valerie this, int unit, char *name )
+{
+       return valerie_execute( this, 1024, "UGET U%d %s", unit, name );
+}
+
+/** Get a units status.
+*/
+
+valerie_error_code valerie_unit_status( valerie this, int unit, valerie_status status )
+{
+       valerie_error_code error = valerie_execute( this, 1024, "USTA U%d", unit );
+       int error_code = valerie_response_get_error_code( this->last_response );
+
+       memset( status, 0, sizeof( valerie_status_t ) );
+       status->unit = unit;
+       if ( error_code == 202 && valerie_response_count( this->last_response ) == 2 )
+               valerie_status_parse( status, valerie_response_get_line( this->last_response, 1 ) );
+       else if ( error_code == 403 )
+               status->status = unit_undefined;
+
+       return error;
+}
+
+/** Transfer the current settings of unit src to unit dest.
+*/
+
+valerie_error_code valerie_unit_transfer( valerie this, int src, int dest )
+{
+       return valerie_execute( this, 1024, "XFER U%d U%d", src, dest );
+}
+
+/** Obtain the parsers notifier.
+*/
+
+valerie_notifier valerie_get_notifier( valerie this )
+{
+       if ( this != NULL )
+               return valerie_parser_get_notifier( this->parser );
+       else
+               return NULL;
+}
+
+/** List the contents of the specified directory.
+*/
+
+valerie_dir valerie_dir_init( valerie this, char *directory )
+{
+       valerie_dir dir = malloc( sizeof( valerie_dir_t ) );
+       if ( dir != NULL )
+       {
+               memset( dir, 0, sizeof( valerie_dir_t ) );
+               dir->directory = strdup( directory );
+               dir->response = valerie_parser_executef( this->parser, "CLS \"%s\"", directory );
+       }
+       return dir;
+}
+
+/** Return the error code associated to the dir.
+*/
+
+valerie_error_code valerie_dir_get_error_code( valerie_dir dir )
+{
+       if ( dir != NULL )
+               return valerie_get_error_code( NULL, dir->response );
+       else
+               return valerie_malloc_failed;
+}
+
+/** Get a particular file entry in the directory.
+*/
+
+valerie_error_code valerie_dir_get( valerie_dir dir, int index, valerie_dir_entry entry )
+{
+       valerie_error_code error = valerie_ok;
+       memset( entry, 0, sizeof( valerie_dir_entry_t ) );
+       if ( index < valerie_dir_count( dir ) )
+       {
+               char *line = valerie_response_get_line( dir->response, index + 1 );
+               valerie_tokeniser tokeniser = valerie_tokeniser_init( );
+               valerie_tokeniser_parse_new( tokeniser, line, " " );
+
+               if ( valerie_tokeniser_count( tokeniser ) > 0 )
+               {
+                       valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 0 ), '\"' );
+                       strcpy( entry->full, dir->directory );
+                       if ( entry->full[ strlen( entry->full ) - 1 ] != '/' )
+                               strcat( entry->full, "/" );
+                       strcpy( entry->name, valerie_tokeniser_get_string( tokeniser, 0 ) );
+                       strcat( entry->full, entry->name );
+
+                       switch ( valerie_tokeniser_count( tokeniser ) )
+                       {
+                               case 1:
+                                       entry->dir = 1;
+                                       break;
+                               case 2:
+                                       entry->size = strtoull( valerie_tokeniser_get_string( tokeniser, 1 ), NULL, 10 );
+                                       break;
+                               default:
+                                       error = valerie_invalid_file;
+                                       break;
+                       }
+               }
+               valerie_tokeniser_close( tokeniser );
+       }
+       return error;
+}
+
+/** Get the number of entries in the directory
+*/
+
+int valerie_dir_count( valerie_dir dir )
+{
+       if ( dir != NULL && valerie_response_count( dir->response ) >= 2 )
+               return valerie_response_count( dir->response ) - 2;
+       else
+               return -1;
+}
+
+/** Close the directory structure.
+*/
+
+void valerie_dir_close( valerie_dir dir )
+{
+       if ( dir != NULL )
+       {
+               free( dir->directory );
+               valerie_response_close( dir->response );
+               free( dir );
+       }
+}
+
+/** List the playlist of the specified unit.
+*/
+
+valerie_list valerie_list_init( valerie this, int unit )
+{
+       valerie_list list = calloc( 1, sizeof( valerie_list_t ) );
+       if ( list != NULL )
+       {
+               list->response = valerie_parser_executef( this->parser, "LIST U%d", unit );
+               if ( valerie_response_count( list->response ) >= 2 )
+                       list->generation = atoi( valerie_response_get_line( list->response, 1 ) );
+       }
+       return list;
+}
+
+/** Return the error code associated to the list.
+*/
+
+valerie_error_code valerie_list_get_error_code( valerie_list list )
+{
+       if ( list != NULL )
+               return valerie_get_error_code( NULL, list->response );
+       else
+               return valerie_malloc_failed;
+}
+
+/** Get a particular file entry in the list.
+*/
+
+valerie_error_code valerie_list_get( valerie_list list, int index, valerie_list_entry entry )
+{
+       valerie_error_code error = valerie_ok;
+       memset( entry, 0, sizeof( valerie_list_entry_t ) );
+       if ( index < valerie_list_count( list ) )
+       {
+               char *line = valerie_response_get_line( list->response, index + 2 );
+               valerie_tokeniser tokeniser = valerie_tokeniser_init( );
+               valerie_tokeniser_parse_new( tokeniser, line, " " );
+
+               if ( valerie_tokeniser_count( tokeniser ) > 0 )
+               {
+                       entry->clip = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) );
+                       valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 1 ), '\"' );
+                       strcpy( entry->full, valerie_tokeniser_get_string( tokeniser, 1 ) );
+                       entry->in = atof( valerie_tokeniser_get_string( tokeniser, 2 ) );
+                       entry->out = atof( valerie_tokeniser_get_string( tokeniser, 3 ) );
+                       entry->max = atof( valerie_tokeniser_get_string( tokeniser, 4 ) );
+                       entry->size = atof( valerie_tokeniser_get_string( tokeniser, 5 ) );
+                       entry->fps = atof( valerie_tokeniser_get_string( tokeniser, 6 ) );
+               }
+               valerie_tokeniser_close( tokeniser );
+       }
+       return error;
+}
+
+/** Get the number of entries in the list
+*/
+
+int valerie_list_count( valerie_list list )
+{
+       if ( list != NULL && valerie_response_count( list->response ) >= 3 )
+               return valerie_response_count( list->response ) - 3;
+       else
+               return -1;
+}
+
+/** Close the list structure.
+*/
+
+void valerie_list_close( valerie_list list )
+{
+       if ( list != NULL )
+       {
+               valerie_response_close( list->response );
+               free( list );
+       }
+}
+
+/** List the currently connected nodes.
+*/
+
+valerie_nodes valerie_nodes_init( valerie this )
+{
+       valerie_nodes nodes = malloc( sizeof( valerie_nodes_t ) );
+       if ( nodes != NULL )
+       {
+               memset( nodes, 0, sizeof( valerie_nodes_t ) );
+               nodes->response = valerie_parser_executef( this->parser, "NLS" );
+       }
+       return nodes;
+}
+
+/** Return the error code associated to the nodes list.
+*/
+
+valerie_error_code valerie_nodes_get_error_code( valerie_nodes nodes )
+{
+       if ( nodes != NULL )
+               return valerie_get_error_code( NULL, nodes->response );
+       else
+               return valerie_malloc_failed;
+}
+
+/** Get a particular node entry.
+*/
+
+valerie_error_code valerie_nodes_get( valerie_nodes nodes, int index, valerie_node_entry entry )
+{
+       valerie_error_code error = valerie_ok;
+       memset( entry, 0, sizeof( valerie_node_entry_t ) );
+       if ( index < valerie_nodes_count( nodes ) )
+       {
+               char *line = valerie_response_get_line( nodes->response, index + 1 );
+               valerie_tokeniser tokeniser = valerie_tokeniser_init( );
+               valerie_tokeniser_parse_new( tokeniser, line, " " );
+
+               if ( valerie_tokeniser_count( tokeniser ) == 3 )
+               {
+                       entry->node = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) );
+                       strncpy( entry->guid, valerie_tokeniser_get_string( tokeniser, 1 ), sizeof( entry->guid ) );
+                       valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 2 ), '\"' );
+                       strncpy( entry->name, valerie_tokeniser_get_string( tokeniser, 2 ), sizeof( entry->name ) );
+               }
+
+               valerie_tokeniser_close( tokeniser );
+       }
+       return error;
+}
+
+/** Get the number of nodes
+*/
+
+int valerie_nodes_count( valerie_nodes nodes )
+{
+       if ( nodes != NULL && valerie_response_count( nodes->response ) >= 2 )
+               return valerie_response_count( nodes->response ) - 2;
+       else
+               return -1;
+}
+
+/** Close the nodes structure.
+*/
+
+void valerie_nodes_close( valerie_nodes nodes )
+{
+       if ( nodes != NULL )
+       {
+               valerie_response_close( nodes->response );
+               free( nodes );
+       }
+}
+
+/** List the currently defined units.
+*/
+
+valerie_units valerie_units_init( valerie this )
+{
+       valerie_units units = malloc( sizeof( valerie_units_t ) );
+       if ( units != NULL )
+       {
+               memset( units, 0, sizeof( valerie_units_t ) );
+               units->response = valerie_parser_executef( this->parser, "ULS" );
+       }
+       return units;
+}
+
+/** Return the error code associated to the nodes list.
+*/
+
+valerie_error_code valerie_units_get_error_code( valerie_units units )
+{
+       if ( units != NULL )
+               return valerie_get_error_code( NULL, units->response );
+       else
+               return valerie_malloc_failed;
+}
+
+/** Get a particular unit entry.
+*/
+
+valerie_error_code valerie_units_get( valerie_units units, int index, valerie_unit_entry entry )
+{
+       valerie_error_code error = valerie_ok;
+       memset( entry, 0, sizeof( valerie_unit_entry_t ) );
+       if ( index < valerie_units_count( units ) )
+       {
+               char *line = valerie_response_get_line( units->response, index + 1 );
+               valerie_tokeniser tokeniser = valerie_tokeniser_init( );
+               valerie_tokeniser_parse_new( tokeniser, line, " " );
+
+               if ( valerie_tokeniser_count( tokeniser ) == 4 )
+               {
+                       entry->unit = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) + 1 );
+                       entry->node = atoi( valerie_tokeniser_get_string( tokeniser, 1 ) );
+                       strncpy( entry->guid, valerie_tokeniser_get_string( tokeniser, 2 ), sizeof( entry->guid ) );
+                       entry->online = atoi( valerie_tokeniser_get_string( tokeniser, 3 ) );
+               }
+
+               valerie_tokeniser_close( tokeniser );
+       }
+       return error;
+}
+
+/** Get the number of units
+*/
+
+int valerie_units_count( valerie_units units )
+{
+       if ( units != NULL && valerie_response_count( units->response ) >= 2 )
+               return valerie_response_count( units->response ) - 2;
+       else
+               return -1;
+}
+
+/** Close the units structure.
+*/
+
+void valerie_units_close( valerie_units units )
+{
+       if ( units != NULL )
+       {
+               valerie_response_close( units->response );
+               free( units );
+       }
+}
+
+/** Get the response of the last command executed.
+*/
+
+valerie_response valerie_get_last_response( valerie this )
+{
+       return this->last_response;
+}
+
+/** Obtain a printable message associated to the error code provided.
+*/
+
+char *valerie_error_description( valerie_error_code error )
+{
+       char *msg = "Unrecognised error";
+       switch( error )
+       {
+               case valerie_ok:
+                       msg = "OK";
+                       break;
+               case valerie_malloc_failed:
+                       msg = "Memory allocation error";
+                       break;
+               case valerie_unknown_error:
+                       msg = "Unknown error";
+                       break;
+               case valerie_no_response:
+                       msg = "No response obtained";
+                       break;
+               case valerie_invalid_command:
+                       msg = "Invalid command";
+                       break;
+               case valerie_server_timeout:
+                       msg = "Communications with server timed out";
+                       break;
+               case valerie_missing_argument:
+                       msg = "Missing argument";
+                       break;
+               case valerie_server_unavailable:
+                       msg = "Unable to communicate with server";
+                       break;
+               case valerie_unit_creation_failed:
+                       msg = "Unit creation failed";
+                       break;
+               case valerie_unit_unavailable:
+                       msg = "Unit unavailable";
+                       break;
+               case valerie_invalid_file:
+                       msg = "Invalid file";
+                       break;
+               case valerie_invalid_position:
+                       msg = "Invalid position";
+                       break;
+       }
+       return msg;
+}
+
+/** Close the valerie structure.
+*/
+
+void valerie_close( valerie this )
+{
+       if ( this != NULL )
+       {
+               valerie_set_last_response( this, NULL );
+               free( this );
+       }
+}
diff --git a/src/valerie/valerie.h b/src/valerie/valerie.h
new file mode 100644 (file)
index 0000000..91c0987
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * valerie.h -- High Level Client API for miracle
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _VALERIE_H_
+#define _VALERIE_H_
+
+/* System header files */
+#include <limits.h>
+
+/* Application header files */
+#include "valerie_parser.h"
+#include "valerie_status.h"
+#include "valerie_notifier.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Client error conditions
+*/
+
+typedef enum
+{
+       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
+}
+valerie_error_code;
+
+/** Clip index specification.
+*/
+
+typedef enum
+{
+       valerie_absolute = 0,
+       valerie_relative
+}
+valerie_clip_offset;
+
+/** Client structure.
+*/
+
+typedef struct
+{
+       valerie_parser parser;
+       valerie_response last_response;
+}
+*valerie, valerie_t;
+
+/** Client API.
+*/
+
+extern valerie valerie_init( valerie_parser );
+
+/* Connect to the valerie parser instance */
+extern valerie_error_code valerie_connect( valerie );
+
+/* Global functions */
+extern valerie_error_code valerie_set( valerie, char *, char * );
+extern valerie_error_code valerie_get( valerie, char *, char *, int );
+extern valerie_error_code valerie_run( valerie, char * );
+
+/* Unit functions */
+extern valerie_error_code valerie_unit_add( valerie, char *, int * );
+extern valerie_error_code valerie_unit_load( valerie, int, char * );
+extern valerie_error_code valerie_unit_load_clipped( valerie, int, char *, double, double );
+extern valerie_error_code valerie_unit_load_back( valerie, int, char * );
+extern valerie_error_code valerie_unit_load_back_clipped( valerie, int, char *, double, double );
+extern valerie_error_code valerie_unit_append( valerie, int, char *, double, double );
+extern valerie_error_code valerie_unit_clean( valerie, int );
+extern valerie_error_code valerie_unit_clip_move( valerie, int, valerie_clip_offset, int, valerie_clip_offset, int );
+extern valerie_error_code valerie_unit_clip_remove( valerie, int, valerie_clip_offset, int );
+extern valerie_error_code valerie_unit_remove_current_clip( valerie, int );
+extern valerie_error_code valerie_unit_clip_insert( valerie, int, valerie_clip_offset, int, char *, double, double );
+extern valerie_error_code valerie_unit_play( valerie, int );
+extern valerie_error_code valerie_unit_play_at_speed( valerie, int, double );
+extern valerie_error_code valerie_unit_stop( valerie, int );
+extern valerie_error_code valerie_unit_pause( valerie, int );
+extern valerie_error_code valerie_unit_rewind( valerie, int );
+extern valerie_error_code valerie_unit_fast_forward( valerie, int );
+extern valerie_error_code valerie_unit_step( valerie, int, double );
+extern valerie_error_code valerie_unit_goto( valerie, int, double );
+extern valerie_error_code valerie_unit_clip_goto( valerie, int, valerie_clip_offset, int, double );
+extern valerie_error_code valerie_unit_clip_set_in( valerie, int, valerie_clip_offset, int, double );
+extern valerie_error_code valerie_unit_clip_set_out( valerie, int, valerie_clip_offset, int, double );
+extern valerie_error_code valerie_unit_set_in( valerie, int, double );
+extern valerie_error_code valerie_unit_set_out( valerie, int, double );
+extern valerie_error_code valerie_unit_clear_in( valerie, int );
+extern valerie_error_code valerie_unit_clear_out( valerie, int );
+extern valerie_error_code valerie_unit_clear_in_out( valerie, int );
+extern valerie_error_code valerie_unit_set( valerie, int, char *, char * );
+extern valerie_error_code valerie_unit_get( valerie, int, char * );
+extern valerie_error_code valerie_unit_status( valerie, int, valerie_status );
+extern valerie_error_code valerie_unit_transfer( valerie, int, int );
+
+/* Notifier functionality. */
+extern valerie_notifier valerie_get_notifier( valerie );
+
+/** Structure for the directory.
+*/
+
+typedef struct
+{
+       char *directory;
+       valerie_response response;
+}
+*valerie_dir, valerie_dir_t;
+
+/** Directory entry structure.
+*/
+
+typedef struct
+{
+       int dir;
+       char name[ NAME_MAX ];
+       char full[ PATH_MAX + NAME_MAX ];
+       unsigned long long size;
+}
+*valerie_dir_entry, valerie_dir_entry_t;
+
+/* Directory reading. */
+extern valerie_dir valerie_dir_init( valerie, char * );
+extern valerie_error_code valerie_dir_get_error_code( valerie_dir );
+extern valerie_error_code valerie_dir_get( valerie_dir, int, valerie_dir_entry );
+extern int valerie_dir_count( valerie_dir );
+extern void valerie_dir_close( valerie_dir );
+
+/** Structure for the list.
+*/
+
+typedef struct
+{
+       int generation;
+       valerie_response response;
+}
+*valerie_list, valerie_list_t;
+
+/** List entry structure.
+*/
+
+typedef struct
+{
+       int clip;
+       char full[ PATH_MAX + NAME_MAX ];
+       double in;
+       double out;
+       double max;
+       double size;
+       double fps;
+}
+*valerie_list_entry, valerie_list_entry_t;
+
+/* List reading. */
+extern valerie_list valerie_list_init( valerie, int );
+extern valerie_error_code valerie_list_get_error_code( valerie_list );
+extern valerie_error_code valerie_list_get( valerie_list, int, valerie_list_entry );
+extern int valerie_list_count( valerie_list );
+extern void valerie_list_close( valerie_list );
+
+/** Structure for nodes.
+*/
+
+typedef struct
+{
+       valerie_response response;
+}
+*valerie_nodes, valerie_nodes_t;
+
+/** Node entry structure.
+*/
+
+typedef struct
+{
+       int node;
+       char guid[ 17 ];
+       char name[ 1024 ];
+}
+*valerie_node_entry, valerie_node_entry_t;
+
+/* Node reading. */
+extern valerie_nodes valerie_nodes_init( valerie );
+extern valerie_error_code valerie_nodes_get_error_code( valerie_nodes );
+extern valerie_error_code valerie_nodes_get( valerie_nodes, int, valerie_node_entry );
+extern int valerie_nodes_count( valerie_nodes );
+extern void valerie_nodes_close( valerie_nodes );
+
+/** Structure for units.
+*/
+
+typedef struct
+{
+       valerie_response response;
+}
+*valerie_units, valerie_units_t;
+
+/** Unit entry structure.
+*/
+
+typedef struct
+{
+       int unit;
+       int node;
+       char guid[ 17 ];
+       int online;
+}
+*valerie_unit_entry, valerie_unit_entry_t;
+
+/* Unit reading. */
+extern valerie_units valerie_units_init( valerie );
+extern valerie_error_code valerie_units_get_error_code( valerie_units );
+extern valerie_error_code valerie_units_get( valerie_units, int, valerie_unit_entry );
+extern int valerie_units_count( valerie_units );
+extern void valerie_units_close( valerie_units );
+
+/* Miscellaenous functions */
+extern valerie_response valerie_get_last_response( valerie );
+extern char *valerie_error_description( valerie_error_code );
+
+/* Courtesy functions. */
+extern valerie_error_code valerie_execute( valerie, size_t, char *, ... );
+
+/* Close function. */
+extern void valerie_close( valerie );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/valerie/valerie_notifier.c b/src/valerie/valerie_notifier.c
new file mode 100644 (file)
index 0000000..5e374a8
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * valerie_notifier.c -- Unit Status Notifier Handling
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+
+/* Application header files */
+#include "valerie_notifier.h"
+
+/** Notifier initialisation.
+*/
+
+valerie_notifier valerie_notifier_init( )
+{
+       valerie_notifier this = malloc( sizeof( valerie_notifier_t ) );
+       if ( this != NULL )
+       {
+               int index = 0;
+               memset( this, 0, sizeof( valerie_notifier_t ) );
+               pthread_mutex_init( &this->mutex, NULL );
+               pthread_cond_init( &this->cond, NULL );
+               pthread_mutex_init( &this->cond_mutex, NULL );
+               for ( index = 0; index < MAX_UNITS; index ++ )
+                       this->store[ index ].unit = index;
+       }
+       return this;
+}
+
+/** Get a stored status for the specified unit.
+*/
+
+void valerie_notifier_get( valerie_notifier this, valerie_status status, int unit )
+{
+       pthread_mutex_lock( &this->mutex );
+       if ( unit >= 0 && unit < MAX_UNITS )
+       {
+               valerie_status_copy( status, &this->store[ unit ] );
+       }
+       else
+       {
+               memset( status, 0, sizeof( valerie_status_t ) );
+               status->unit = unit;
+       }
+       status->dummy = time( NULL );
+       pthread_mutex_unlock( &this->mutex );
+}
+
+/** Wait on a new status.
+*/
+
+int valerie_notifier_wait( valerie_notifier this, valerie_status status )
+{
+       struct timeval now;
+       struct timespec timeout;
+       int error = 0;
+
+       memset( status, 0, sizeof( valerie_status_t ) );
+
+       pthread_mutex_lock( &this->cond_mutex );
+       gettimeofday( &now, NULL );
+       timeout.tv_sec = now.tv_sec + 1;
+       timeout.tv_nsec = now.tv_usec * 1000;
+       if ( pthread_cond_timedwait( &this->cond, &this->cond_mutex, &timeout ) != ETIMEDOUT )
+       {
+               pthread_mutex_lock( &this->mutex );
+               valerie_status_copy( status, &this->last );
+               pthread_mutex_unlock( &this->mutex );
+       }
+       else
+       {
+               error = -1;
+       }
+       pthread_mutex_unlock( &this->cond_mutex );
+
+       return error;
+}
+
+/** Put a new status.
+*/
+
+void valerie_notifier_put( valerie_notifier this, valerie_status status )
+{
+       pthread_mutex_lock( &this->mutex );
+       valerie_status_copy( &this->store[ status->unit ], status );
+       valerie_status_copy( &this->last, status );
+       pthread_mutex_unlock( &this->mutex );
+       pthread_cond_broadcast( &this->cond );
+}
+
+/** Communicate a disconnected status for all units to all waiting.
+*/
+
+void valerie_notifier_disconnected( valerie_notifier notifier )
+{
+       int unit = 0;
+       valerie_status_t status;
+       for ( unit = 0; unit < MAX_UNITS; unit ++ )
+       {
+               valerie_notifier_get( notifier, &status, unit );
+               status.status = unit_disconnected;
+               valerie_notifier_put( notifier, &status );
+       }
+}
+
+/** Close the notifier - note that all access must be stopped before we call this.
+*/
+
+void valerie_notifier_close( valerie_notifier this )
+{
+       if ( this != NULL )
+       {
+               pthread_mutex_destroy( &this->mutex );
+               pthread_mutex_destroy( &this->cond_mutex );
+               pthread_cond_destroy( &this->cond );
+               free( this );
+       }
+}
diff --git a/src/valerie/valerie_notifier.h b/src/valerie/valerie_notifier.h
new file mode 100644 (file)
index 0000000..bc123ed
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * valerie_notifier.h -- Unit Status Notifier Handling
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_NOTIFIER_H_
+#define _VALERIE_NOTIFIER_H_
+
+/* System header files */
+#include <pthread.h>
+
+/* Application header files */
+#include "valerie_status.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define MAX_UNITS 16
+
+/** Status notifier definition.
+*/
+
+typedef struct
+{
+       pthread_mutex_t mutex;
+       pthread_mutex_t cond_mutex;
+       pthread_cond_t cond;
+       valerie_status_t last;
+       valerie_status_t store[ MAX_UNITS ];
+}
+*valerie_notifier, valerie_notifier_t;
+
+extern valerie_notifier valerie_notifier_init( );
+extern void valerie_notifier_get( valerie_notifier, valerie_status, int );
+extern int valerie_notifier_wait( valerie_notifier, valerie_status );
+extern void valerie_notifier_put( valerie_notifier, valerie_status );
+extern void valerie_notifier_disconnected( valerie_notifier );
+extern void valerie_notifier_close( valerie_notifier );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/valerie/valerie_parser.c b/src/valerie/valerie_parser.c
new file mode 100644 (file)
index 0000000..4ead1c0
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * valerie_parser.c -- Valerie Parser for Miracle
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Application header files */
+#include "valerie_parser.h"
+#include "valerie_util.h"
+
+/** Connect to the parser.
+*/
+
+valerie_response valerie_parser_connect( valerie_parser parser )
+{
+       return parser->connect( parser->real );
+}
+
+/** Execute a command via the parser.
+*/
+
+valerie_response valerie_parser_execute( valerie_parser parser, char *command )
+{
+       return parser->execute( parser->real, command );
+}
+
+/** Execute a formatted command via the parser.
+*/
+
+valerie_response valerie_parser_executef( valerie_parser parser, char *format, ... )
+{
+       char *command = malloc( 10240 );
+       valerie_response response = NULL;
+       if ( command != NULL )
+       {
+               va_list list;
+               va_start( list, format );
+               if ( vsnprintf( command, 10240, format, list ) != 0 )
+                       response = valerie_parser_execute( parser, command );
+               va_end( list );
+               free( command );
+       }
+       return response;
+}
+
+/** Execute the contents of a file. Note the special case valerie_response returned.
+*/
+
+valerie_response valerie_parser_run( valerie_parser parser, char *filename )
+{
+       valerie_response response = valerie_response_init( );
+       if ( response != NULL )
+       {
+               FILE *file = fopen( filename, "r" );
+               if ( file != NULL )
+               {
+                       char command[ 1024 ];
+                       valerie_response_set_error( response, 201, "OK" );
+                       while ( valerie_response_get_error_code( response ) == 201 && fgets( command, 1024, file ) )
+                       {
+                               valerie_util_trim( valerie_util_chomp( command ) );
+                               if ( strcmp( command, "" ) && command[ 0 ] != '#' )
+                               {
+                                       valerie_response temp = NULL;
+                                       valerie_response_printf( response, 1024, "%s\n", command );
+                                       temp = valerie_parser_execute( parser, command );
+                                       if ( temp != NULL )
+                                       {
+                                               int index = 0;
+                                               for ( index = 0; index < valerie_response_count( temp ); index ++ )
+                                                       valerie_response_printf( response, 10240, "%s\n", valerie_response_get_line( temp, index ) );
+                                               valerie_response_close( temp );
+                                       }
+                                       else
+                                       {
+                                               valerie_response_set_error( response, 500, "Batch execution failed" );
+                                       }
+                               }
+                       }
+                       fclose( file );
+               }
+               else
+               {
+                       valerie_response_set_error( response, 404, "File not found." );
+               }
+       }
+       return response;
+}
+
+/** Get the notifier associated to the parser.
+*/
+
+valerie_notifier valerie_parser_get_notifier( valerie_parser parser )
+{
+       if ( parser->notifier == NULL )
+               parser->notifier = valerie_notifier_init( );
+       return parser->notifier;
+}
+
+/** Close the parser.
+*/
+
+void valerie_parser_close( valerie_parser parser )
+{
+       if ( parser != NULL )
+       {
+               parser->close( parser->real );
+               valerie_notifier_close( parser->notifier );
+               free( parser );
+       }
+}
diff --git a/src/valerie/valerie_parser.h b/src/valerie/valerie_parser.h
new file mode 100644 (file)
index 0000000..71446d9
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * valerie_parser.h -- Valerie Parser for Miracle Server
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_PARSER_H_
+#define _VALERIE_PARSER_H_
+
+/* Application header files */
+#include "valerie_response.h"
+#include "valerie_notifier.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Callbacks to define the parser.
+*/
+
+typedef valerie_response (*parser_connect)( void * );
+typedef valerie_response (*parser_execute)( void *, char * );
+typedef void (*parser_close)( void * );
+
+/** Structure for the valerie parser.
+*/
+
+typedef struct
+{
+       parser_connect connect;
+       parser_execute execute;
+       parser_close close;
+       void *real;
+       valerie_notifier notifier;
+}
+*valerie_parser, valerie_parser_t;
+
+/** API for the parser - note that no constructor is defined here.
+*/
+
+extern valerie_response valerie_parser_connect( valerie_parser );
+extern valerie_response valerie_parser_execute( valerie_parser, char * );
+extern valerie_response valerie_parser_executef( valerie_parser, char *, ... );
+extern valerie_response valerie_parser_run( valerie_parser, char * );
+extern valerie_notifier valerie_parser_get_notifier( valerie_parser );
+extern void valerie_parser_close( valerie_parser );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/valerie/valerie_remote.c b/src/valerie/valerie_remote.c
new file mode 100644 (file)
index 0000000..4b5023e
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * valerie_remote.c -- Remote Parser
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <pthread.h>
+
+/* Application header files */
+#include "valerie_remote.h"
+#include "valerie_socket.h"
+#include "valerie_tokeniser.h"
+#include "valerie_util.h"
+
+/** Private valerie_remote structure.
+*/
+
+typedef struct
+{
+       int terminated;
+       char *server;
+       int port;
+       valerie_socket socket;
+       valerie_socket status;
+       pthread_t thread;
+       valerie_parser parser;
+       pthread_mutex_t mutex;
+       int connected;
+}
+*valerie_remote, valerie_remote_t;
+
+/** Forward declarations.
+*/
+
+static valerie_response valerie_remote_connect( valerie_remote );
+static valerie_response valerie_remote_execute( valerie_remote, char * );
+static void valerie_remote_close( valerie_remote );
+static int valerie_remote_read_response( valerie_socket, valerie_response );
+
+/** DV Parser constructor.
+*/
+
+valerie_parser valerie_parser_init_remote( char *server, int port )
+{
+       valerie_parser parser = malloc( sizeof( valerie_parser_t ) );
+       valerie_remote remote = malloc( sizeof( valerie_remote_t ) );
+
+       if ( parser != NULL )
+       {
+               memset( parser, 0, sizeof( valerie_parser_t ) );
+
+               parser->connect = (parser_connect)valerie_remote_connect;
+               parser->execute = (parser_execute)valerie_remote_execute;
+               parser->close = (parser_close)valerie_remote_close;
+               parser->real = remote;
+
+               if ( remote != NULL )
+               {
+                       memset( remote, 0, sizeof( valerie_remote_t ) );
+                       remote->parser = parser;
+                       remote->server = strdup( server );
+                       remote->port = port;
+                       pthread_mutex_init( &remote->mutex, NULL );
+               }
+       }
+       return parser;
+}
+
+/** Thread for receiving and distributing the status information.
+*/
+
+static void *valerie_remote_status_thread( void *arg )
+{
+       valerie_remote remote = arg;
+       char temp[ 10240 ];
+       int length = 0;
+       int offset = 0;
+       valerie_tokeniser tokeniser = valerie_tokeniser_init( );
+       valerie_notifier notifier = valerie_parser_get_notifier( remote->parser );
+       valerie_status_t status;
+       int index = 0;
+
+       valerie_socket_write_data( remote->status, "STATUS\r\n", 8 );
+
+       while ( !remote->terminated && 
+                       ( length = valerie_socket_read_data( remote->status, temp + offset, sizeof( temp ) ) ) >= 0 )
+       {
+               if ( strchr( temp, '\n' ) == NULL )
+               {
+                       offset = length;
+                       continue;
+               }
+               offset = 0;
+               valerie_tokeniser_parse_new( tokeniser, temp, "\n" );
+               for ( index = 0; index < valerie_tokeniser_count( tokeniser ); index ++ )
+               {
+                       char *line = valerie_tokeniser_get_string( tokeniser, index );
+                       if ( line[ strlen( line ) - 1 ] == '\r' )
+                       {
+                               valerie_util_chomp( line );
+                               valerie_status_parse( &status, line );
+                               valerie_notifier_put( notifier, &status );
+                       }
+                       else
+                       {
+                               strcpy( temp, line );
+                               offset = strlen( temp );
+                       }
+               }
+       }
+
+       valerie_notifier_disconnected( notifier );
+       valerie_tokeniser_close( tokeniser );
+       remote->terminated = 1;
+
+       return NULL;
+}
+
+/** Forward reference.
+*/
+
+static void valerie_remote_disconnect( valerie_remote remote );
+
+/** Connect to the server.
+*/
+
+static valerie_response valerie_remote_connect( valerie_remote remote )
+{
+       valerie_response response = NULL;
+
+       valerie_remote_disconnect( remote );
+
+       if ( !remote->connected )
+       {
+               signal( SIGPIPE, SIG_IGN );
+
+               remote->socket = valerie_socket_init( remote->server, remote->port );
+               remote->status = valerie_socket_init( remote->server, remote->port );
+
+               if ( valerie_socket_connect( remote->socket ) == 0 )
+               {
+                       response = valerie_response_init( );
+                       valerie_remote_read_response( remote->socket, response );
+               }
+
+               if ( response != NULL && valerie_socket_connect( remote->status ) == 0 )
+               {
+                       valerie_response status_response = valerie_response_init( );
+                       valerie_remote_read_response( remote->status, status_response );
+                       if ( valerie_response_get_error_code( status_response ) == 100 )
+                               pthread_create( &remote->thread, NULL, valerie_remote_status_thread, remote );
+                       valerie_response_close( status_response );
+                       remote->connected = 1;
+               }
+       }
+
+       return response;
+}
+
+/** Execute the command.
+*/
+
+static valerie_response valerie_remote_execute( valerie_remote remote, char *command )
+{
+       valerie_response response = NULL;
+       pthread_mutex_lock( &remote->mutex );
+       if ( valerie_socket_write_data( remote->socket, command, strlen( command ) ) == strlen( command ) )
+       {
+               response = valerie_response_init( );
+               valerie_socket_write_data( remote->socket, "\r\n", 2 );
+               valerie_remote_read_response( remote->socket, response );
+       }
+       pthread_mutex_unlock( &remote->mutex );
+       return response;
+}
+
+/** Disconnect.
+*/
+
+static void valerie_remote_disconnect( valerie_remote remote )
+{
+       if ( remote != NULL && remote->terminated )
+       {
+               pthread_join( remote->thread, NULL );
+               valerie_socket_close( remote->status );
+               valerie_socket_close( remote->socket );
+               remote->connected = 0;
+               remote->terminated = 0;
+       }
+}
+
+/** Close the parser.
+*/
+
+static void valerie_remote_close( valerie_remote remote )
+{
+       if ( remote != NULL )
+       {
+               remote->terminated = 1;
+               valerie_remote_disconnect( remote );
+               pthread_mutex_destroy( &remote->mutex );
+               free( remote->server );
+               free( remote );
+       }
+}
+
+/** Read response. 
+*/
+
+static int valerie_remote_read_response( valerie_socket socket, valerie_response response )
+{
+       char temp[ 10240 ];
+       int length;
+       int terminated = 0;
+
+       while ( !terminated && ( length = valerie_socket_read_data( socket, temp, 10240 ) ) >= 0 )
+       {
+               int position = 0;
+               temp[ length ] = '\0';
+               valerie_response_write( response, temp, length );
+               position = valerie_response_count( response ) - 1;
+               if ( position < 0 || temp[ strlen( temp ) - 1 ] != '\n' )
+                       continue;
+               switch( valerie_response_get_error_code( response ) )
+               {
+                       case 201:
+                       case 500:
+                               terminated = !strcmp( valerie_response_get_line( response, position ), "" );
+                               break;
+                       case 202:
+                               terminated = valerie_response_count( response ) >= 2;
+                               break;
+                       default:
+                               terminated = 1;
+                               break;
+               }
+       }
+
+       return 0;
+}
diff --git a/src/valerie/valerie_remote.h b/src/valerie/valerie_remote.h
new file mode 100644 (file)
index 0000000..291184a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * valerie_remote.h -- Remote Parser
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_REMOTE_H_
+#define _VALERIE_REMOTE_H_
+
+/* Application header files */
+#include "valerie_parser.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Remote parser API.
+*/
+
+extern valerie_parser valerie_parser_init_remote( char *, int );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/valerie/valerie_response.c b/src/valerie/valerie_response.c
new file mode 100644 (file)
index 0000000..5b9491c
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * valerie_response.c -- Response
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+/* Application header files */
+#include "valerie_response.h"
+
+/** Construct a new dv response.
+*/
+
+valerie_response valerie_response_init( )
+{
+       valerie_response response = malloc( sizeof( valerie_response_t ) );
+       if ( response != NULL )
+               memset( response, 0, sizeof( valerie_response_t ) );
+       return response;
+}
+
+/** Clone a dv response
+*/
+
+valerie_response valerie_response_clone( valerie_response response )
+{
+       valerie_response clone = valerie_response_init( );
+       if ( clone != NULL && response != NULL )
+       {
+               int index = 0;
+               for ( index = 0; index < valerie_response_count( response ); index ++ )
+               {
+                       char *line = valerie_response_get_line( response, index );
+                       valerie_response_printf( clone, strlen( line ) + 2, "%s\n", line );
+               }
+       }
+       return clone;
+}
+
+/** Get the error code associated to the response.
+*/
+
+int valerie_response_get_error_code( valerie_response response )
+{
+       int error_code = -1;
+       if ( response != NULL )
+       {
+               if ( response->count > 0 )
+               {
+                       if ( sscanf( response->array[ 0 ], "%d", &error_code ) != 1 )
+                               error_code = 0;
+               }
+               else
+               {
+                       error_code = -2;
+               }
+       }
+       return error_code;
+}
+
+/** Get the error description associated to the response.
+*/
+
+char *valerie_response_get_error_string( valerie_response response )
+{
+       char *error_string = "No message specified";
+       if ( response->count > 0 )
+       {
+               char *ptr = strchr( response->array[ 0 ], ' ' ) ;
+               if ( ptr != NULL )
+                       error_string = ptr + 1;
+       }
+       return error_string;
+}
+
+/** Get a line of text at the given index. Note that the text itself is
+       terminated only with a NUL char and it is the responsibility of the
+       the user of the returned data to use a LF or CR/LF as appropriate.
+*/
+
+char *valerie_response_get_line( valerie_response response, int index )
+{
+       if ( index < response->count )
+               return response->array[ index ];
+       else
+               return NULL;
+}
+
+/** Return the number of lines of text in the response.
+*/
+
+int valerie_response_count( valerie_response response )
+{
+       if ( response != NULL )
+               return response->count;
+       else
+               return 0;
+}
+
+/** Set the error and description associated to the response.
+*/
+
+void valerie_response_set_error( valerie_response response, int error_code, char *error_string )
+{
+       if ( response->count == 0 )
+       {
+               valerie_response_printf( response, 10240, "%d %s\n", error_code, error_string );
+       }
+       else
+       {
+               char temp[ 10240 ];
+               int length = sprintf( temp, "%d %s", error_code, error_string );
+               response->array[ 0 ] = realloc( response->array[ 0 ], length + 1 );
+               strcpy( response->array[ 0 ], temp );
+       }
+}
+
+/** Write formatted text to the response. 
+*/
+
+int valerie_response_printf( valerie_response response, size_t size, char *format, ... )
+{
+       int length = 0;
+       char *text = malloc( size );
+       if ( text != NULL )
+       {
+               va_list list;
+               va_start( list, format );
+               length = vsnprintf( text, size, format, list );
+               if ( length != 0 )
+                       valerie_response_write( response, text, length );
+               va_end( list );
+               free( text );
+       }
+       return length;
+}
+
+/** Write text to the reponse.
+*/
+
+int valerie_response_write( valerie_response response, char *text, int size )
+{
+       int ret = 0;
+       char *ptr = text;
+
+       while ( size > 0 )
+       {
+               int index = response->count - 1;
+               char *lf = strchr( ptr, '\n' );
+               int length_of_string = 0;
+
+               /* Make sure we have space in the dynamic array. */
+               if ( !response->append && response->count >= response->size - 1 )
+               {
+                       response->size += 50;
+                       response->array = realloc( response->array, response->size * sizeof( char * ) );
+               }
+
+               /* Make sure the array is valid, or we're really in trouble */
+               if ( response->array == NULL )
+               {
+                       ret = 0;
+                       break;
+               }
+
+               /* Now, if we're appending to the previous write (ie: if it wasn't
+                  terminated by a LF), then use the index calculated above, otherwise
+                  go to the next one and ensure it's NULLed. */
+
+               if ( !response->append )
+               {
+                       response->array[ ++ index ] = NULL;
+                       response->count ++;
+               }
+               else
+               {
+                       length_of_string = strlen( response->array[ index ] );
+               }
+
+               /* Now we need to know how to handle the current ptr with respect to lf. */
+               /* TODO: tidy up and error check... sigh... tested for many, many 1000s of lines */
+
+               if ( lf == NULL )
+               {
+                       response->array[ index ] = realloc( response->array[ index ], length_of_string + size + 1 );
+                       memcpy( response->array[ index ] + length_of_string, ptr, size );
+                       response->array[ index ][ length_of_string + size ] = '\0';
+                       if ( ( length_of_string + size ) > 0 && response->array[ index ][ length_of_string + size - 1 ] == '\r' )
+                               response->array[ index ][ length_of_string + size - 1 ] = '\0';
+                       size = 0;
+                       ret += size;
+                       response->append = 1;
+               }
+               else
+               {
+                       int chars = lf - ptr;
+                       response->array[ index ] = realloc( response->array[ index ], length_of_string + chars + 1 );
+                       memcpy( response->array[ index ] + length_of_string, ptr, chars );
+                       response->array[ index ][ length_of_string + chars ] = '\0';
+                       if ( ( length_of_string + chars ) > 0 && response->array[ index ][ length_of_string + chars - 1 ] == '\r' )
+                               response->array[ index ][ length_of_string + chars - 1 ] = '\0';
+                       ptr = ptr + chars + 1;
+                       size -= ( chars + 1 );
+                       response->append = 0;
+                       ret += chars + 1;
+               }
+       }
+
+       return ret;
+}
+
+/** Close the response.
+*/
+
+void valerie_response_close( valerie_response response )
+{
+       if ( response != NULL )
+       {
+               int index = 0;
+               for ( index = 0; index < response->count; index ++ )
+                       free( response->array[ index ] );
+               free( response->array );
+               free( response );
+       }
+}
diff --git a/src/valerie/valerie_response.h b/src/valerie/valerie_response.h
new file mode 100644 (file)
index 0000000..1e8f1fa
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * valerie_response.h -- Response
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_RESPONSE_H_
+#define _VALERIE_RESPONSE_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Structure for the response
+*/
+
+typedef struct
+{
+       char **array;
+       int size;
+       int count;
+       int append;
+}
+*valerie_response, valerie_response_t;
+
+/** API for accessing the response structure.
+*/
+
+extern valerie_response valerie_response_init( );
+extern valerie_response valerie_response_clone( valerie_response );
+extern int valerie_response_get_error_code( valerie_response );
+extern char *valerie_response_get_error_string( valerie_response );
+extern char *valerie_response_get_line( valerie_response, int );
+extern int valerie_response_count( valerie_response );
+extern void valerie_response_set_error( valerie_response, int, char * );
+extern int valerie_response_printf( valerie_response, size_t, char *, ... );
+extern int valerie_response_write( valerie_response, char *, int );
+extern void valerie_response_close( valerie_response );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/valerie/valerie_socket.c b/src/valerie/valerie_socket.c
new file mode 100644 (file)
index 0000000..74e8483
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * valerie_socket.c -- Client Socket
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* Application header files */
+#include "valerie_socket.h"
+
+/** Initialise the socket.
+*/
+
+valerie_socket valerie_socket_init( char *server, int port )
+{
+       valerie_socket socket = malloc( sizeof( valerie_socket_t ) );
+       if ( socket != NULL )
+       {
+               memset( socket, 0, sizeof( valerie_socket_t ) );
+               socket->fd = -1;
+               socket->server = strdup( server );
+               socket->port = port;
+       }
+       return socket;
+}
+
+/** Connect to the server.
+*/
+
+int valerie_socket_connect( valerie_socket connection )
+{
+       int ret = 0;
+    struct hostent *host;
+    struct sockaddr_in sock;
+
+       if ( connection->server != NULL )
+       {               
+               host = gethostbyname( connection->server );
+       
+               memset( &sock, 0, sizeof( struct sockaddr_in ) );
+               memcpy( &sock.sin_addr, host->h_addr, host->h_length );
+               sock.sin_family = host->h_addrtype;
+               sock.sin_port = htons( connection->port );
+       
+               if ( ( connection->fd = socket( AF_INET, SOCK_STREAM, 0 ) ) != -1 )
+                       ret = connect( connection->fd, (const struct sockaddr *)&sock, sizeof( struct sockaddr_in ) );
+               else
+                       ret = -1;
+       }
+       
+       return ret;     
+}
+
+/** Convenience constructor for a connected file descriptor.
+*/
+
+valerie_socket valerie_socket_init_fd( int fd )
+{
+       valerie_socket socket = malloc( sizeof( valerie_socket_t ) );
+       if ( socket != NULL )
+       {
+               memset( socket, 0, sizeof( valerie_socket_t ) );
+               socket->fd = fd;
+               socket->no_close = 1;
+       }
+       return socket;
+}
+
+/** Read an arbitrarily formatted block of data from the server.
+*/
+
+int valerie_socket_read_data( valerie_socket socket, char *data, int length )
+{
+    struct timeval tv = { 1, 0 };
+    fd_set rfds;
+       int used = 0;
+
+       data[ 0 ] = '\0';
+
+    FD_ZERO( &rfds );
+    FD_SET( socket->fd, &rfds );
+
+       if ( select( socket->fd + 1, &rfds, NULL, NULL, &tv ) )
+       {
+               used = read( socket->fd, data, length - 1 );
+               if ( used > 0 )
+                       data[ used ] = '\0';
+               else
+                       used = -1;
+       }
+
+       return used;
+}      
+
+/** Write an arbitrarily formatted block of data to the server.
+*/
+
+int valerie_socket_write_data( valerie_socket socket, char *data, int length )
+{
+       int used = 0;
+       
+       while ( used >=0 && used < length )
+       {
+               struct timeval tv = { 1, 0 };
+               fd_set rfds;
+               fd_set wfds;
+               fd_set efds;
+       
+               FD_ZERO( &rfds );
+               FD_SET( socket->fd, &rfds );
+               FD_ZERO( &wfds );
+               FD_SET( socket->fd, &wfds );
+               FD_ZERO( &efds );
+               FD_SET( socket->fd, &efds );
+       
+               errno = 0;
+
+               if ( select( socket->fd + 1, &rfds, &wfds, &efds, &tv ) )
+               {
+                       if ( errno != 0 || FD_ISSET( socket->fd, &efds ) || FD_ISSET( socket->fd, &rfds ) )
+                       {
+                               used = -1;
+                       }
+                       else if ( FD_ISSET( socket->fd, &wfds ) )
+                       {
+                               int inc = write( socket->fd, data + used, length - used );
+                               if ( inc > 0 )
+                                       used += inc;
+                               else
+                                       used = -1;
+                       }
+               }
+       }
+
+       return used;
+}
+
+/** Close the socket.
+*/
+
+void valerie_socket_close( valerie_socket socket )
+{
+       if ( socket->fd > 0 && !socket->no_close )
+               close( socket->fd );
+       free( socket->server );
+       free( socket );
+}
diff --git a/src/valerie/valerie_socket.h b/src/valerie/valerie_socket.h
new file mode 100644 (file)
index 0000000..f016ca1
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * valerie_socket.h -- Client Socket
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _VALERIE_SOCKET_H_
+#define _VALERIE_SOCKET_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Structure for socket.
+*/
+
+typedef struct
+{
+       char *server;
+       int port;
+       int fd;
+       int no_close;
+}
+*valerie_socket, valerie_socket_t;
+
+/** Remote parser API.
+*/
+
+extern valerie_socket valerie_socket_init( char *, int );
+extern int valerie_socket_connect( valerie_socket );
+extern valerie_socket valerie_socket_init_fd( int );
+extern int valerie_socket_read_data( valerie_socket, char *, int );
+extern int valerie_socket_write_data( valerie_socket, char *, int );
+extern void valerie_socket_close( valerie_socket );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/valerie/valerie_status.c b/src/valerie/valerie_status.c
new file mode 100644 (file)
index 0000000..5725b0c
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * valerie_status.c -- Unit Status Handling
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Application header files */
+#include "valerie_status.h"
+#include "valerie_tokeniser.h"
+#include "valerie_util.h"
+
+/** Parse a unit status string.
+*/
+
+void valerie_status_parse( valerie_status status, char *text )
+{
+       valerie_tokeniser tokeniser = valerie_tokeniser_init( );
+       if ( valerie_tokeniser_parse_new( tokeniser, text, " " ) == 17 )
+       {
+               status->unit = atoi( valerie_tokeniser_get_string( tokeniser, 0 ) );
+               strncpy( status->clip, valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 2 ), '\"' ), sizeof( status->clip ) );
+               status->position = atof( valerie_tokeniser_get_string( tokeniser, 3 ) );
+               status->speed = atoi( valerie_tokeniser_get_string( tokeniser, 4 ) );
+               status->fps = atof( valerie_tokeniser_get_string( tokeniser, 5 ) );
+               status->in = atof( valerie_tokeniser_get_string( tokeniser, 6 ) );
+               status->out = atof( valerie_tokeniser_get_string( tokeniser, 7 ) );
+               status->length = atof( valerie_tokeniser_get_string( tokeniser, 8 ) );
+
+               strncpy( status->tail_clip, valerie_util_strip( valerie_tokeniser_get_string( tokeniser, 9 ), '\"' ), sizeof( status->tail_clip ) );
+               status->tail_position = atof( valerie_tokeniser_get_string( tokeniser, 10 ) );
+               status->tail_in = atof( valerie_tokeniser_get_string( tokeniser, 11 ) );
+               status->tail_out = atof( valerie_tokeniser_get_string( tokeniser, 12 ) );
+               status->tail_length = atof( valerie_tokeniser_get_string( tokeniser, 13 ) );
+               status->seek_flag = atof( valerie_tokeniser_get_string( tokeniser, 14 ) );
+               status->generation = atof( valerie_tokeniser_get_string( tokeniser, 15 ) );
+               status->clip_index = atof( valerie_tokeniser_get_string( tokeniser, 16 ) );
+
+               if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "unknown" ) )
+                       status->status = unit_unknown;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "undefined" ) )
+                       status->status = unit_undefined;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "offline" ) )
+                       status->status = unit_offline;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "not_loaded" ) )
+                       status->status = unit_not_loaded;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "stopped" ) )
+                       status->status = unit_stopped;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "paused" ) )
+                       status->status = unit_paused;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "playing" ) )
+                       status->status = unit_playing;
+               else if ( !strcmp( valerie_tokeniser_get_string( tokeniser, 1 ), "disconnected" ) )
+                       status->status = unit_disconnected;
+       }
+       else
+       {
+               memset( status, 0, sizeof( valerie_status_t ) );
+               fprintf( stderr, "Status thread changed?\n" );
+       }
+       valerie_tokeniser_close( tokeniser );
+}
+
+/** Serialise a status into a string.
+*/
+
+char *valerie_status_serialise( valerie_status status, char *text, int length )
+{
+       char *status_string = NULL;
+
+       switch( status->status )
+       {
+               case unit_undefined:
+                       status_string = "undefined";
+                       break;
+
+               case unit_offline:
+                       status_string = "offline";
+                       break;
+
+               case unit_not_loaded:
+                       status_string = "not_loaded";
+                       break;
+
+               case unit_stopped:
+                       status_string = "stopped";
+                       break;
+
+               case unit_playing:
+                       status_string = "playing";
+                       break;
+
+               case unit_unknown:
+                       status_string = "unknown";
+                       break;
+
+               case unit_paused:
+                       status_string = "paused";
+                       break;
+
+               case unit_disconnected:
+                       status_string = "disconnected";
+                       break;
+       }
+
+       snprintf( text, length, "%d %s \"%s\" %e %e %.2f %e %e %e \"%s\" %e %e %e %e %d %d %d\r\n",
+                                                       status->unit,
+                                                       status_string,
+                                                       status->clip,
+                                                       status->position, 
+                                                       status->speed,
+                                                       status->fps,
+                                                       status->in,
+                                                       status->out,
+                                                       status->length,
+                                                       status->tail_clip,
+                                                       status->tail_position, 
+                                                       status->tail_in,
+                                                       status->tail_out,
+                                                       status->tail_length,
+                                                       status->seek_flag,
+                                                       status->generation,
+                                                       status->clip_index );
+
+       return text;
+}
+
+/** Compare two status codes for changes.
+*/
+
+int valerie_status_compare( valerie_status status1, valerie_status status2 )
+{
+       return memcmp( status1, status2, sizeof( valerie_status_t ) );
+}
+
+/** Copy status code info from dest to src.
+*/
+
+valerie_status valerie_status_copy( valerie_status dest, valerie_status src )
+{
+       return memcpy( dest, src, sizeof( valerie_status_t ) );
+}
diff --git a/src/valerie/valerie_status.h b/src/valerie/valerie_status.h
new file mode 100644 (file)
index 0000000..d0e45a9
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * valerie_status.h -- Unit Status Handling
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_STATUS_H_
+#define _VALERIE_STATUS_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Status codes
+*/
+
+typedef enum
+{
+       unit_unknown = 0,
+       unit_undefined,
+       unit_offline,
+       unit_not_loaded,
+       unit_stopped,
+       unit_playing,
+       unit_paused,
+       unit_disconnected
+}
+unit_status;
+
+/** Status structure.
+*/
+
+typedef struct
+{
+       int unit;
+       unit_status status;
+       char clip[ 2048 ];
+       double position;
+       double speed;
+       double fps;
+       double in;
+       double out;
+       double length;
+       char tail_clip[ 2048 ];
+       double tail_position;
+       double tail_in;
+       double tail_out;
+       double tail_length;
+       int seek_flag;
+       int generation;
+       int clip_index;
+       int dummy;
+}
+*valerie_status, valerie_status_t;
+
+/** DV1394 Status API
+*/
+
+extern void valerie_status_parse( valerie_status, char * );
+extern char *valerie_status_serialise( valerie_status, char *, int );
+extern int valerie_status_compare( valerie_status, valerie_status );
+extern valerie_status valerie_status_copy( valerie_status, valerie_status );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/valerie/valerie_tokeniser.c b/src/valerie/valerie_tokeniser.c
new file mode 100644 (file)
index 0000000..7acaf85
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * valerie_tokeniser.c -- String tokeniser
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <stdlib.h>
+#include <string.h>
+
+/* Application header files */
+#include "valerie_tokeniser.h"
+
+/** Initialise a tokeniser.
+*/
+
+valerie_tokeniser valerie_tokeniser_init( )
+{
+       valerie_tokeniser tokeniser = malloc( sizeof( valerie_tokeniser_t ) );
+       if ( tokeniser != NULL )
+               memset( tokeniser, 0, sizeof( valerie_tokeniser_t ) );
+       return tokeniser;
+}
+
+/** Clear the tokeniser.
+*/
+
+static void valerie_tokeniser_clear( valerie_tokeniser tokeniser )
+{
+       int index = 0;
+       for ( index = 0; index < tokeniser->count; index ++ )
+               free( tokeniser->tokens[ index ] );
+       tokeniser->count = 0;
+       free( tokeniser->input );
+       tokeniser->input = NULL;
+}
+
+/** Append a string to the tokeniser.
+*/
+
+static int valerie_tokeniser_append( valerie_tokeniser tokeniser, char *token )
+{
+       int error = 0;
+
+       if ( tokeniser->count == tokeniser->size )
+       {
+               tokeniser->size += 20;
+               tokeniser->tokens = realloc( tokeniser->tokens, tokeniser->size * sizeof( char * ) );
+       }
+
+       if ( tokeniser->tokens != NULL )
+       {
+               tokeniser->tokens[ tokeniser->count ++ ] = strdup( token );
+       }
+       else
+       {
+               tokeniser->count = 0;
+               error = -1;
+       }
+       return error;
+}
+
+/** Parse a string by splitting on the delimiter provided.
+*/
+
+int valerie_tokeniser_parse_new( valerie_tokeniser tokeniser, char *string, char *delimiter )
+{
+       int count = 0;
+       int length = strlen( string );
+       int delimiter_size = strlen( delimiter );
+       int index = 0;
+       char *token = strdup( string );
+
+       valerie_tokeniser_clear( tokeniser );
+       tokeniser->input = strdup( string );
+       strcpy( token, "" );
+
+       for ( index = 0; index < length; )
+       {
+               char *start = string + index;
+               char *end = strstr( start, delimiter );
+
+               if ( end == NULL )
+               {
+                       strcat( token, start );
+                       valerie_tokeniser_append( tokeniser, token );
+                       index = length;
+                       count ++;
+               }
+               else if ( start != end )
+               {
+                       strncat( token, start, end - start );
+                       index += end - start;
+                       if ( token[ 0 ] != '\"' || ( token[ 0 ] == '\"' && token[ strlen( token ) - 1 ] == '\"' ) )
+                       {
+                               valerie_tokeniser_append( tokeniser, token );
+                               strcpy( token, "" );
+                               count ++;
+                       }
+                       else while ( strncmp( string + index, delimiter, delimiter_size ) == 0 )
+                       {
+                               strncat( token, delimiter, delimiter_size );
+                               index += delimiter_size;
+                       }
+               }
+               else
+               {
+                       index += strlen( delimiter );
+               }
+       }
+
+       /* Special case - malformed string condition */
+       if ( !strcmp( token, "" ) )
+       {
+               count = 0 - ( count - 1 );
+               valerie_tokeniser_append( tokeniser, token );
+       }
+               
+       free( token );
+       return count;
+}
+
+/** Get the original input.
+*/
+
+char *valerie_tokeniser_get_input( valerie_tokeniser tokeniser )
+{
+       return tokeniser->input;
+}
+
+/** Get the number of tokens.
+*/
+
+int valerie_tokeniser_count( valerie_tokeniser tokeniser )
+{
+       return tokeniser->count;
+}
+
+/** Get a token as a string.
+*/
+
+char *valerie_tokeniser_get_string( valerie_tokeniser tokeniser, int index )
+{
+       if ( index < tokeniser->count )
+               return tokeniser->tokens[ index ];
+       else
+               return NULL;
+}
+
+/** Close the tokeniser.
+*/
+
+void valerie_tokeniser_close( valerie_tokeniser tokeniser )
+{
+       valerie_tokeniser_clear( tokeniser );
+       free( tokeniser->tokens );
+       free( tokeniser );
+}
diff --git a/src/valerie/valerie_tokeniser.h b/src/valerie/valerie_tokeniser.h
new file mode 100644 (file)
index 0000000..9d0838c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * valerie_tokeniser.h -- String tokeniser
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_TOKENISER_H_
+#define _VALERIE_TOKENISER_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Structure for tokeniser.
+*/
+
+typedef struct
+{
+       char *input;
+       char **tokens;
+       int count;
+       int size;
+}
+*valerie_tokeniser, valerie_tokeniser_t;
+
+/** Remote parser API.
+*/
+
+extern valerie_tokeniser valerie_tokeniser_init( );
+extern int valerie_tokeniser_parse_new( valerie_tokeniser, char *, char * );
+extern char *valerie_tokeniser_get_input( valerie_tokeniser );
+extern int valerie_tokeniser_count( valerie_tokeniser );
+extern char *valerie_tokeniser_get_string( valerie_tokeniser, int );
+extern void valerie_tokeniser_close( valerie_tokeniser );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/valerie/valerie_util.c b/src/valerie/valerie_util.c
new file mode 100644 (file)
index 0000000..168f6a7
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * valerie_util.c -- General Purpose Client Utilities
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* System header files */
+#include <string.h>
+#include <ctype.h>
+
+/* Application header files */
+#include "valerie_util.h"
+
+/** Remove LF or CR/LF terminations from the input string.
+*/
+
+char *valerie_util_chomp( char *input )
+{
+       if ( input != NULL )
+       {
+               int length = strlen( input );
+               if ( length && input[ length - 1 ] == '\n' )
+                       input[ length - 1 ] = '\0';
+               if ( length > 1 && input[ length - 2 ] == '\r' )
+                       input[ length - 2 ] = '\0';
+       }
+       return input;
+}
+
+/** Remove leading and trailing spaces from the input string.
+*/
+
+char *valerie_util_trim( char *input )
+{
+       if ( input != NULL )
+       {
+               int length = strlen( input );
+               int first = 0;
+               while( first < length && isspace( input[ first ] ) )
+                       first ++;
+               memmove( input, input + first, length - first + 1 );
+               length = length - first;
+               while ( length > 0 && isspace( input[ length - 1 ] ) )
+                       input[ -- length ] = '\0';
+       }
+       return input;
+}
+
+/** Strip the specified string of leading and trailing 'value' (ie: ").
+*/
+
+char *valerie_util_strip( char *input, char value )
+{
+       if ( input != NULL )
+       {
+               char *ptr = strrchr( input, value );
+               if ( ptr != NULL )
+                       *ptr = '\0';
+               if ( input[ 0 ] == value )
+                       strcpy( input, input + 1 );
+       }
+       return input;
+}
diff --git a/src/valerie/valerie_util.h b/src/valerie/valerie_util.h
new file mode 100644 (file)
index 0000000..492eba0
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * valerie_util.h -- General Purpose Client Utilities
+ * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _VALERIE_UTIL_H_
+#define _VALERIE_UTIL_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+extern char *valerie_util_chomp( char * );
+extern char *valerie_util_trim( char * );
+extern char *valerie_util_strip( char *, char );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif