diff --git a/csri/Doxyfile b/csri/Doxyfile
new file mode 100644
index 000000000..1fe4e6ad9
--- /dev/null
+++ b/csri/Doxyfile
@@ -0,0 +1,22 @@
+PROJECT_NAME = CSRI
+PROJECT_NUMBER = 0.1
+OUTPUT_DIRECTORY = doc
+
+JAVADOC_AUTOBRIEF = YES
+OPTIMIZE_OUTPUT_FOR_C = YES
+PREDEFINED = DOXYGEN
+ENUM_VALUES_PER_LINE = 1
+EXPAND_AS_DEFINED = _CSRI_H _CSRI_HELPER_H
+
+INPUT = include/csri include/subhelp.h
+FILE_PATTERNS = *.h
+RECURSIVE = YES
+
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+
+GENERATE_MAN = YES
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+
diff --git a/csri/LICENSE b/csri/LICENSE
new file mode 100644
index 000000000..32bccc30c
--- /dev/null
+++ b/csri/LICENSE
@@ -0,0 +1,31 @@
+Copyright (c) 2007, David Lamparter
+All rights reserved.
+
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+
diff --git a/csri/Makefile.am b/csri/Makefile.am
new file mode 100644
index 000000000..1c0752cc5
--- /dev/null
+++ b/csri/Makefile.am
@@ -0,0 +1,12 @@
+AUTOMAKE_OPTIONS = foreign
+EXTRA_DIST = csri.pc.in acinclude.m4
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = csri.pc
+
+SUBDIRS = ac \
+ include \
+ subhelp \
+ lib \
+ backends \
+ frontends
diff --git a/csri/ac/Makefile.am b/csri/ac/Makefile.am
new file mode 100644
index 000000000..c8c87da1a
--- /dev/null
+++ b/csri/ac/Makefile.am
@@ -0,0 +1,3 @@
+EXTRA_DIST = \
+ csri.sln \
+ subhelp.vcproj
diff --git a/csri/ac/csri.sln b/csri/ac/csri.sln
new file mode 100644
index 000000000..98d1eafb1
--- /dev/null
+++ b/csri/ac/csri.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "subhelp", "subhelp.vcproj", "{870552FE-7B73-41AB-A7D9-475440F4731C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {870552FE-7B73-41AB-A7D9-475440F4731C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {870552FE-7B73-41AB-A7D9-475440F4731C}.Debug|Win32.Build.0 = Debug|Win32
+ {870552FE-7B73-41AB-A7D9-475440F4731C}.Release|Win32.ActiveCfg = Release|Win32
+ {870552FE-7B73-41AB-A7D9-475440F4731C}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/csri/ac/subhelp.vcproj b/csri/ac/subhelp.vcproj
new file mode 100644
index 000000000..004d4b065
--- /dev/null
+++ b/csri/ac/subhelp.vcproj
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/csri/acinclude.m4 b/csri/acinclude.m4
new file mode 100644
index 000000000..dc8bd2bab
--- /dev/null
+++ b/csri/acinclude.m4
@@ -0,0 +1,67 @@
+dnl AC_CPP_PRAGMA_ONCE
+dnl - check for #pragma once
+AC_DEFUN([AC_CPP_PRAGMA_ONCE], [{
+ AC_MSG_CHECKING([[whether $CPP supports #pragma once]])
+ AC_PREPROC_IFELSE(
+ [AC_LANG_PROGRAM([[#pragma once]])],
+ [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_PRAGMA_ONCE], [1], [Preprocessor support for #pragma once])
+ ],
+ [AC_MSG_RESULT([no])])
+ }])
+
+dnl AC_C_FLAG([-flag])
+dnl - check for CFLAG support in CC
+AC_DEFUN([AC_C_FLAG], [{
+ AC_LANG_PUSH(C)
+ ac_c_flag_save="$CFLAGS"
+ CFLAGS="$CFLAGS $1"
+ AC_MSG_CHECKING([[whether $CC supports $1]])
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([[]])],
+ [
+ AC_MSG_RESULT([yes])
+ m4_if([$3], [], [], [
+ CFLAGS="$ac_c_flag_save"
+ $3
+ ])
+ ], [
+ CFLAGS="$ac_c_flag_save"
+ AC_MSG_RESULT([no])
+ $2
+ ])
+ AC_LANG_POP(C)
+ }])
+
+dnl AC_C_FLAG([-flag])
+dnl - check for CFLAG support in CC
+AC_DEFUN([AC_GCC_VISIBILITY], [{
+ AC_MSG_CHECKING([[whether $CC supports GCC visibility]])
+ # always use Werror since visibility is sensitive
+ # doesn't work on anything other than gcc either way, so Werror is fine...
+ vis_type="$1"
+ save_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -fvisibility=$vis_type -Werror"
+ AC_LINK_IFELSE(
+ [AC_LANG_SOURCE([[
+ int a() __attribute__((visibility("default")));
+ int b() __attribute__((visibility("hidden")));
+ int c() __attribute__((visibility("internal")));
+
+ int a() { return 1; }
+ int b() { return 2; }
+ int c() { return 3; }
+
+ int main() { return a()+b()+c(); }
+ ]])],
+ [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_GCC_VISIBILITY], [1], [Compiler support for GCC visibility attributes])
+ save_cflags="$save_cflags -fvisibility=$vis_type"
+ ],
+ [AC_MSG_RESULT([no])]
+ )
+ CFLAGS="$save_cflags"
+ }])
+
diff --git a/csri/backends/Makefile.am b/csri/backends/Makefile.am
new file mode 100644
index 000000000..514d9a69d
--- /dev/null
+++ b/csri/backends/Makefile.am
@@ -0,0 +1,4 @@
+if BUILD_LIBASS
+LIBASS_DIR = libass
+endif
+SUBDIRS = $(LIBASS_DIR)
diff --git a/csri/backends/libass/Makefile.am b/csri/backends/libass/Makefile.am
new file mode 100644
index 000000000..9ec4801fb
--- /dev/null
+++ b/csri/backends/libass/Makefile.am
@@ -0,0 +1,6 @@
+csrilib_LTLIBRARIES = libass_csri.la
+libass_csri_la_SOURCES = libass_csri.c
+libass_csri_la_LDFLAGS = -avoid-version -no-undefined
+libass_csri_la_LIBADD = ../../subhelp/libsubhelp_la-openfile.lo $(LIBASS_LIBS)
+libass_csri_la_CFLAGS = -I$(top_srcdir)/include $(LIBASS_CFLAGS)
+
diff --git a/csri/backends/libass/libass_csri.c b/csri/backends/libass/libass_csri.c
new file mode 100644
index 000000000..295b182d6
--- /dev/null
+++ b/csri/backends/libass/libass_csri.c
@@ -0,0 +1,258 @@
+/*****************************************************************************
+ * csri: common subtitle renderer interface
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+/** libass csri wrapper.
+ * Indirectly based on code from aegisub,
+ * (c) 2006-2007, Rodrigo Braz Monteiro, Evgeniy Stepanov
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "acconf.h"
+#endif
+
+#include
+#include
+#include
+
+#include
+
+#ifdef _WIN32
+# define CSRIAPI __declspec(dllexport)
+#else
+# ifdef HAVE_GCC_VISIBILITY
+# define CSRIAPI __attribute__((visibility ("default")))
+# else
+# define CSRIAPI
+# endif
+#endif
+
+#define CSRI_OWN_HANDLES
+typedef struct csri_libass_rend {
+ ass_library_t* ass_library;
+} csri_rend;
+
+typedef struct csri_asa_inst {
+ ass_renderer_t* ass_renderer;
+ ass_track_t* ass_track;
+} csri_inst;
+
+#include
+#include
+#include
+
+static struct csri_libass_rend csri_libass = { NULL };
+
+csri_inst *csri_open_file(csri_rend *renderer,
+ const char *filename, struct csri_openflag *flags)
+{
+ return subhelp_open_file(renderer, csri_open_mem, filename, flags);
+}
+
+csri_inst *csri_open_mem(csri_rend *renderer,
+ const void *data, size_t length, struct csri_openflag *flags)
+{
+ csri_inst *rv;
+ if (renderer != &csri_libass)
+ return NULL;
+
+ rv = (csri_inst *)malloc(sizeof(csri_inst));
+ if (!rv)
+ return NULL;
+
+ rv->ass_renderer = ass_renderer_init(renderer->ass_library);
+ if (!rv->ass_renderer) {
+ free(rv);
+ return NULL;
+ }
+ ass_set_font_scale(rv->ass_renderer, 1.);
+ ass_set_fonts(rv->ass_renderer, NULL, "Sans");
+ rv->ass_track = ass_read_memory(csri_libass.ass_library,
+ (void *)data, length, "UTF-8");
+ if (!rv->ass_track) {
+ ass_renderer_done(rv->ass_renderer);
+ free(rv);
+ return NULL;
+ }
+ return rv;
+}
+
+void csri_close(csri_inst *inst)
+{
+ ass_free_track(inst->ass_track);
+ ass_renderer_done(inst->ass_renderer);
+ free(inst);
+}
+
+int csri_request_fmt(csri_inst *inst, const struct csri_fmt *fmt)
+{
+ if (!csri_is_rgb(fmt->pixfmt) || csri_has_alpha(fmt->pixfmt))
+ return -1;
+ ass_set_frame_size(inst->ass_renderer, fmt->width, fmt->height);
+ return 0;
+}
+
+void csri_render(csri_inst *inst, struct csri_frame *frame, double time)
+{
+ ass_image_t *img = ass_render_frame(inst->ass_renderer,
+ inst->ass_track, (int)(time * 1000), NULL);
+
+ while (img) {
+ unsigned bpp, alpha = 256 - (img->color && 0xFF);
+ int src_d, dst_d;
+ unsigned char *src, *dst, *endy, *endx;
+ unsigned char c[3] = {
+ (img->color >> 8) & 0xFF, /* B */
+ (img->color >> 16) & 0xFF, /* G */
+ img->color >> 24 /* R */
+ };
+ if ((frame->pixfmt | 1) == CSRI_F__RGB
+ || frame->pixfmt == CSRI_F_RGB) {
+ unsigned char tmp = c[2];
+ c[2] = c[0];
+ c[0] = tmp;
+ }
+ bpp = frame->pixfmt >= 0x200 ? 3 : 4;
+
+ dst = frame->planes[0]
+ + img->dst_y * frame->strides[0]
+ + img->dst_x * bpp;
+ if (frame->pixfmt & 1)
+ dst++;
+ src = img->bitmap;
+
+ src_d = img->stride - img->w;
+ dst_d = frame->strides[0] - img->w * bpp;
+ endy = src + img->h * img->stride;
+
+ while (src != endy) {
+ endx = src + img->w;
+ while (src != endx) {
+ /* src[x]: 0..255, alpha: 1..256 (see above)
+ * -> src[x]*alpha: 0<<8..255<<8
+ * -> need 1..256 for mult => +1
+ */
+ unsigned s = ((*src++ * alpha) >> 8) + 1;
+ unsigned d = 257 - s;
+ /* c[0]: 0.255, s/d: 1..256 */
+ dst[0] = (s*c[0] + d*dst[0]) >> 8;
+ dst[1] = (s*c[1] + d*dst[1]) >> 8;
+ dst[2] = (s*c[2] + d*dst[2]) >> 8;
+ dst += bpp;
+ }
+ dst += dst_d;
+ src += src_d;
+ }
+ img = img->next;
+ }
+}
+
+static csri_inst *libass_init_stream(csri_rend *renderer,
+ const void *header, size_t headerlen,
+ struct csri_openflag *flags)
+{
+ csri_inst *rv;
+
+ if (renderer != &csri_libass)
+ return NULL;
+
+ rv = (csri_inst *)malloc(sizeof(csri_inst));
+ if (!rv)
+ return NULL;
+
+ rv->ass_renderer = ass_renderer_init(renderer->ass_library);
+ if (!rv->ass_renderer) {
+ free(rv);
+ return NULL;
+ }
+ ass_set_font_scale(rv->ass_renderer, 1.);
+ ass_set_fonts(rv->ass_renderer, NULL, "Sans");
+ rv->ass_track = ass_new_track(csri_libass.ass_library);
+ if (!rv->ass_track) {
+ ass_renderer_done(rv->ass_renderer);
+ free(rv);
+ return NULL;
+ }
+ ass_process_codec_private(rv->ass_track, (void *)header, headerlen);
+ return rv;
+}
+
+static void libass_push_packet(csri_inst *inst,
+ const void *packet, size_t packetlen,
+ double pts_start, double pts_end)
+{
+ ass_process_chunk(inst->ass_track, (void *)packet, packetlen,
+ (int)(pts_start * 1000), (int)((pts_end - pts_start) * 1000));
+}
+
+static struct csri_stream_ext streamext = {
+ libass_init_stream,
+ libass_push_packet,
+ NULL
+};
+
+void *csri_query_ext(csri_rend *rend, csri_ext_id extname)
+{
+ if (!rend)
+ return NULL;
+ if (!strcmp(extname, CSRI_EXT_STREAM_ASS))
+ return &streamext;
+ return NULL;
+}
+
+static struct csri_info csri_libass_info = {
+ "libass",
+ "0.9.x",
+ "libass (the MPlayer SSA/ASS renderer, 0.9.x API)",
+ "Evgeniy Stepanov",
+ "Copyright (c) 2006, 2007 by Evgeniy Stepanov"
+};
+
+struct csri_info *csri_renderer_info(csri_rend *rend)
+{
+ return &csri_libass_info;
+}
+
+csri_rend *csri_renderer_byname(const char *name,
+ const char *specific)
+{
+ if (strcmp(name, csri_libass_info.name))
+ return NULL;
+ if (specific && strcmp(specific, csri_libass_info.specific))
+ return NULL;
+ return &csri_libass;
+}
+
+csri_rend *csri_renderer_default()
+{
+ csri_libass.ass_library = ass_library_init();
+ if (!csri_libass.ass_library)
+ return NULL;
+
+ ass_set_fonts_dir(csri_libass.ass_library, "");
+ ass_set_extract_fonts(csri_libass.ass_library, 0);
+ ass_set_style_overrides(csri_libass.ass_library, NULL);
+ return &csri_libass;
+}
+
+csri_rend *csri_renderer_next(csri_rend *prev)
+{
+ return NULL;
+}
+
diff --git a/csri/bootstrap b/csri/bootstrap
new file mode 100755
index 000000000..f3a56638d
--- /dev/null
+++ b/csri/bootstrap
@@ -0,0 +1,4 @@
+#!/bin/bash -x
+
+autoreconf -f -i -s
+
diff --git a/csri/configure.ac b/csri/configure.ac
new file mode 100644
index 000000000..d009c61b7
--- /dev/null
+++ b/csri/configure.ac
@@ -0,0 +1,135 @@
+AC_PREREQ(2.57)
+AC_INIT(csri, 0.1.0)
+AC_CONFIG_AUX_DIR(ac)
+AM_INIT_AUTOMAKE
+AC_CONFIG_HEADER([include/acconf.h])
+
+# Checks for programs.
+AC_PROG_CC
+
+AC_PROG_LIBTOOL
+AC_C_CONST
+AC_C_INLINE
+AC_C_VOLATILE
+
+AC_PROG_INSTALL
+
+AC_CHECK_HEADERS([png.h])
+AC_CHECK_LIB([z], [inflate])
+AC_CHECK_LIB([m], [pow])
+AC_CHECK_LIB([png], [png_init_io])
+
+AC_CPP_PRAGMA_ONCE
+AC_C_FLAG([-Wall])
+AC_C_FLAG([-Wextra],[AC_C_FLAG([-W])])
+AC_C_FLAG([-Wno-unused-parameter])
+AC_C_FLAG([-Winvalid-pch])
+AC_C_FLAG([-pedantic])
+AC_C_FLAG([-std=c99],[AC_C_FLAG([-c99])])
+AC_ARG_ENABLE([werror],
+ AC_HELP_STRING([--enable-werror], [compile with -Werror (for developers)]),
+ [ if test "$enableval" == "yes"
+ then AC_C_FLAG([-Werror])
+ fi])
+AC_GCC_VISIBILITY([internal])
+
+AC_PATH_XTRA
+platform=""
+case $host_os in
+mingw*) # LoadLibraryEx + GetProcAddress
+ platform="win32"
+ ;;
+*) AC_SEARCH_LIBS([dlopen], [dl], [], [
+ AC_MSG_FAILURE([dlopen not found - unsupported dynamic loader architecture / operating system])
+ ])
+esac
+
+AM_CONDITIONAL([BUILD_MINGW], [test "$platform" == "win32" ])
+
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_STDBOOL
+AC_CHECK_HEADERS([stdlib.h string.h sys/ioctl.h sys/time.h sys/wait.h sys/mman.h unistd.h libgen.h getopt.h])
+AC_CHECK_FUNCS([getopt_long])
+#
+# Checks for typedefs, structures, and compiler characteristics.
+# Checks for library functions.
+#AC_FUNC_FORK
+#AC_PROG_GCC_TRADITIONAL
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_TYPE_SIGNAL
+AC_FUNC_MEMCMP
+AC_CHECK_FUNCS([memset strdup strerror strtoul])
+
+AC_ARG_WITH([libass],[
+ AS_HELP_STRING([--with-libass],[build libass backend @<:@default=auto@:>@])
+],[],[ with_libass=auto
+])
+
+libass=no
+AS_IF([test "$with_libass" != no],[
+ ac_cflags_save="$CFLAGS"
+ ac_ldflags_save="$LDFLAGS"
+
+ if test "$with_libass" != auto -a "$with_libass" != yes
+ then LIBASS_CFLAGS="-I$with_libass/include"
+ LIBASS_LIBS="-L$with_libass/lib -lass"
+ else PKG_CHECK_MODULES([LIBASS], libass >= 0.9.1,[],[
+ AC_MSG_WARN([libass not found via pkg-config])
+ LIBASS_LIBS="-lass"
+ ])
+ fi
+ CFLAGS="$CFLAGS $LIBASS_CFLAGS"
+ LDFLAGS="$LDFLAGS $LIBASS_LIBS"
+
+ AC_CHECK_LIB([ass], [ass_library_init], [libass_lib="yes"])
+ AC_CHECK_HEADER([ass/ass.h], [libass_hdr="yes"])
+
+ if test "$libass_lib" == yes -a "$libass_hdr" == yes
+ then libass=yes
+ else if "$with_libass" != auto
+ then AC_MSG_FAILURE([libass requested but not found])
+ fi
+ fi
+ CFLAGS="$ac_cflags_save"
+ LDFLAGS="$ac_ldflags_save"
+])
+AM_CONDITIONAL([BUILD_LIBASS], [test "$libass" == "yes" ])
+AC_SUBST([LIBASS_CFLAGS])
+AC_SUBST([LIBASS_LIBS])
+
+csrilibdir="${libdir}/csri"
+AC_SUBST([csrilibdir])
+
+csri_path="${csrilibdir}:/usr/lib/csri:/usr/local/lib/csri:~/.csri/lib"
+AC_ARG_WITH(csri-libpath,
+ AC_HELP_STRING([--with-csri-libpath=PATH1:PATH2],
+ [Look for CSRI renderers in the specified directories. Separate directory names with colons. Tildes are expanded at run-time. [[$csri_path]]]),
+[
+ if test "$withval" != "yes" -a "$withval" != "" -a "$withval" != "no"
+ then csri_path="$withval"
+ fi
+])
+AC_SUBST([csri_path], ["$csri_path"])
+
+AC_CONFIG_FILES([csri.pc])
+
+echo ""
+echo " using search path: ${csri_path}"
+echo "building libass wrapper: ${libass}"
+echo ""
+AC_OUTPUT([
+ ac/Makefile
+ include/Makefile
+ subhelp/Makefile
+ lib/Makefile
+ frontends/Makefile
+ frontends/avisynth25/Makefile
+ frontends/cmdline/Makefile
+ backends/Makefile
+ backends/libass/Makefile
+ Makefile
+])
+
diff --git a/csri/csri.pc.in b/csri/csri.pc.in
new file mode 100644
index 000000000..ad79302b9
--- /dev/null
+++ b/csri/csri.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: csri
+Description: csri - common subtitle renderer interface
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lcsri
+Cflags: -I${includedir}
diff --git a/csri/csri.vcproj b/csri/csri.vcproj
new file mode 100644
index 000000000..3bf6c0338
--- /dev/null
+++ b/csri/csri.vcproj
@@ -0,0 +1,328 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/csri/csri_2008.vcproj b/csri/csri_2008.vcproj
new file mode 100644
index 000000000..b266e3192
--- /dev/null
+++ b/csri/csri_2008.vcproj
@@ -0,0 +1,327 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/csri/frontends/Makefile.am b/csri/frontends/Makefile.am
new file mode 100644
index 000000000..9676881c3
--- /dev/null
+++ b/csri/frontends/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = \
+ avisynth25 \
+ cmdline
+
diff --git a/csri/frontends/avisynth25/Makefile.am b/csri/frontends/avisynth25/Makefile.am
new file mode 100644
index 000000000..b5977f0a7
--- /dev/null
+++ b/csri/frontends/avisynth25/Makefile.am
@@ -0,0 +1,15 @@
+if BUILD_MINGW
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include
+lib_LTLIBRARIES = csri_avs.la
+csri_avs_la_SOURCES = avisynth.cpp
+csri_avs_la_LIBADD = \
+ ../../lib/libcsri_la-enumerate.lo \
+ ../../lib/libcsri_la-list.lo \
+ ../../lib/libcsri_la-wrap.lo \
+ ../../subhelp/libsubhelp_la-logging.lo
+csri_avs_la_LDFLAGS = -avoid-version -no-undefined -module
+endif
+
+noinst_HEADERS = avisynth.h
+EXTRA_DIST = avisynth.cpp
diff --git a/csri/frontends/avisynth25/avisynth.cpp b/csri/frontends/avisynth25/avisynth.cpp
new file mode 100644
index 000000000..bde755c49
--- /dev/null
+++ b/csri/frontends/avisynth25/avisynth.cpp
@@ -0,0 +1,155 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2006 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#include
+#include "avisynth.h"
+#include
+
+#include
+
+class CSRIAviSynth : public GenericVideoFilter {
+ csri_inst *inst;
+ double spf;
+
+public:
+ CSRIAviSynth(PClip _child, IScriptEnvironment *env, const char *file,
+ const char *rendname, const char *rendver);
+ ~CSRIAviSynth();
+
+ enum csri_pixfmt GetPixfmt();
+
+ PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment *env);
+
+ static AVSValue __cdecl Create(AVSValue args, void* user_data,
+ IScriptEnvironment* env);
+};
+
+CSRIAviSynth::CSRIAviSynth(PClip _child, IScriptEnvironment *env,
+ const char *file, const char *rendname, const char *rendver)
+ : GenericVideoFilter(_child)
+{
+ csri_rend *r = csri_renderer_byname(rendname, rendver);
+ if (!r) {
+ if (rendver)
+ env->ThrowError("Failed to load renderer \"%s\""
+ " version \"%s\"", rendname, rendver);
+ else if (rendname)
+ env->ThrowError("Failed to load renderer \"%s\"",
+ rendname);
+ else
+ env->ThrowError("Failed to load default renderer");
+ }
+
+ struct csri_fmt fmt;
+ fmt.pixfmt = GetPixfmt();
+ if (fmt.pixfmt == -1)
+ env->ThrowError("Pixel format not supported by "
+ "AviSynth interface");
+
+ inst = csri_open_file(r, file, NULL);
+ if (!inst)
+ env->ThrowError("Failed to load \"%s\"", file);
+
+ fmt.width = vi.width;
+ fmt.height = vi.height;
+ if (csri_request_fmt(inst, &fmt)) {
+ csri_close(inst);
+ env->ThrowError("Selected pixel format or size not supported "
+ "by selected subtitle renderer", file);
+ }
+ spf = (double)vi.fps_denominator / (double)vi.fps_numerator;
+}
+
+CSRIAviSynth::~CSRIAviSynth()
+{
+ csri_close(inst);
+}
+
+enum csri_pixfmt CSRIAviSynth::GetPixfmt()
+{
+ switch (vi.pixel_type) {
+ case VideoInfo::CS_BGR24: return CSRI_F_BGR;
+ case VideoInfo::CS_BGR32: return CSRI_F_BGR_;
+ case VideoInfo::CS_YUY2: return CSRI_F_YUY2;
+ case VideoInfo::CS_YV12: return CSRI_F_YV12;
+ }
+ return (enum csri_pixfmt)-1;
+}
+
+PVideoFrame __stdcall CSRIAviSynth::GetFrame(int n, IScriptEnvironment *env)
+{
+ PVideoFrame avsframe = child->GetFrame(n, env);
+ struct csri_frame frame;
+
+ env->MakeWritable(&avsframe);
+
+ frame.pixfmt = GetPixfmt();
+ frame.planes[0] = avsframe->GetWritePtr();
+ frame.strides[0] = avsframe->GetPitch();
+ if (csri_is_yuv_planar(frame.pixfmt)) {
+ frame.planes[1] = avsframe->GetWritePtr(PLANAR_U);
+ frame.strides[1] = avsframe->GetPitch(PLANAR_U);
+ frame.planes[2] = avsframe->GetWritePtr(PLANAR_V);
+ frame.strides[2] = avsframe->GetPitch(PLANAR_V);
+ }
+ if (csri_is_rgb(frame.pixfmt)) {
+ frame.planes[0] += (vi.height - 1) * frame.strides[0];
+ frame.strides[0] = -frame.strides[0];
+ }
+
+ csri_render(inst, &frame, n * spf);
+ return avsframe;
+}
+
+AVSValue __cdecl CSRIAviSynth::Create(AVSValue args, void* user_data,
+ IScriptEnvironment* env)
+{
+ const char *rname = args.ArraySize() >= 2 ? args[2].AsString() : NULL,
+ *rver = args.ArraySize() >= 3 ? args[3].AsString() : NULL;
+ return new CSRIAviSynth(args[0].AsClip(), env, args[1].AsString(),
+ rname, rver);
+}
+
+extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(
+ IScriptEnvironment* env)
+{
+ static char avs_name_f[2048];
+ const char *avs_cmdname = (const char *)csri_query_ext(NULL,
+ "csri.avisynth25.command_name");
+ const char *avs_name = (const char *)csri_query_ext(NULL,
+ "csri.avisynth25.name");
+
+ if (!csri_renderer_default())
+ return NULL;
+
+ if (!avs_cmdname)
+ avs_cmdname = "CSRI";
+ if (!avs_name)
+ avs_name = "Common Subtitle Renderer Interface";
+
+ env->AddFunction(avs_cmdname, "cs", CSRIAviSynth::Create, 0);
+ env->AddFunction(avs_cmdname, "css", CSRIAviSynth::Create, 0);
+ env->AddFunction(avs_cmdname, "csss", CSRIAviSynth::Create, 0);
+
+ snprintf(avs_name_f, sizeof(avs_name_f),
+ "%s [AviSynth 2.5 front-end]", avs_name);
+ return avs_name_f;
+}
+
diff --git a/csri/frontends/avisynth25/avisynth.h b/csri/frontends/avisynth25/avisynth.h
new file mode 100644
index 000000000..d0a543aa3
--- /dev/null
+++ b/csri/frontends/avisynth25/avisynth.h
@@ -0,0 +1,754 @@
+// Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al.
+// http://www.avisynth.org
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
+// http://www.gnu.org/copyleft/gpl.html .
+//
+// Linking Avisynth statically or dynamically with other modules is making a
+// combined work based on Avisynth. Thus, the terms and conditions of the GNU
+// General Public License cover the whole combination.
+//
+// As a special exception, the copyright holders of Avisynth give you
+// permission to link Avisynth with independent modules that communicate with
+// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
+// terms of these independent modules, and to copy and distribute the
+// resulting combined work under terms of your choice, provided that
+// every copy of the combined work is accompanied by a complete copy of
+// the source code of Avisynth (the version of Avisynth used to produce the
+// combined work), being distributed under the terms of the GNU General
+// Public License plus this exception. An independent module is a module
+// which is not derived from or based on Avisynth, such as 3rd-party filters,
+// import and export plugins, or graphical user interfaces.
+
+
+
+
+
+#ifndef __AVISYNTH_H__
+#define __AVISYNTH_H__
+
+enum { AVISYNTH_INTERFACE_VERSION = 3 };
+
+
+/* Define all types necessary for interfacing with avisynth.dll
+ Moved from internal.h */
+
+// Win32 API macros, notably the types BYTE, DWORD, ULONG, etc.
+#include
+
+// COM interface macros
+#include
+
+
+// Raster types used by VirtualDub & Avisynth
+#define in64 (__int64)(unsigned short)
+typedef unsigned long Pixel; // this will break on 64-bit machines!
+typedef unsigned long Pixel32;
+typedef unsigned char Pixel8;
+typedef long PixCoord;
+typedef long PixDim;
+typedef long PixOffset;
+
+
+/* Compiler-specific crap */
+
+// Tell MSVC to stop precompiling here
+#ifdef _MSC_VER
+ #pragma hdrstop
+#endif
+
+// Set up debugging macros for MS compilers; for others, step down to the
+// standard interface
+#ifdef _MSC_VER
+ #include
+#else
+ #define _RPT0(a,b) ((void)0)
+ #define _RPT1(a,b,c) ((void)0)
+ #define _RPT2(a,b,c,d) ((void)0)
+ #define _RPT3(a,b,c,d,e) ((void)0)
+ #define _RPT4(a,b,c,d,e,f) ((void)0)
+
+ #define _ASSERTE(x) assert(x)
+ #define _ASSERT(x) assert(x)
+ #include
+#endif
+
+
+
+// I had problems with Premiere wanting 1-byte alignment for its structures,
+// so I now set the Avisynth struct alignment explicitly here.
+#pragma pack(push,8)
+
+#define FRAME_ALIGN 16
+// Default frame alignment is 16 bytes, to help P4, when using SSE2
+
+// The VideoInfo struct holds global information about a clip (i.e.
+// information that does not depend on the frame number). The GetVideoInfo
+// method in IClip returns this struct.
+
+// Audio Sample information
+typedef float SFLOAT;
+
+enum {SAMPLE_INT8 = 1<<0,
+ SAMPLE_INT16 = 1<<1,
+ SAMPLE_INT24 = 1<<2, // Int24 is a very stupid thing to code, but it's supported by some hardware.
+ SAMPLE_INT32 = 1<<3,
+ SAMPLE_FLOAT = 1<<4};
+
+enum {
+ PLANAR_Y=1<<0,
+ PLANAR_U=1<<1,
+ PLANAR_V=1<<2,
+ PLANAR_ALIGNED=1<<3,
+ PLANAR_Y_ALIGNED=PLANAR_Y|PLANAR_ALIGNED,
+ PLANAR_U_ALIGNED=PLANAR_U|PLANAR_ALIGNED,
+ PLANAR_V_ALIGNED=PLANAR_V|PLANAR_ALIGNED,
+ };
+
+struct VideoInfo {
+ int width, height; // width=0 means no video
+ unsigned fps_numerator, fps_denominator;
+ int num_frames;
+ // This is more extensible than previous versions. More properties can be added seeminglesly.
+
+ // Colorspace properties.
+ enum {
+ CS_BGR = 1<<28,
+ CS_YUV = 1<<29,
+ CS_INTERLEAVED = 1<<30,
+ CS_PLANAR = 1<<31
+ };
+
+ // Specific colorformats
+ enum { CS_UNKNOWN = 0,
+ CS_BGR24 = 1<<0 | CS_BGR | CS_INTERLEAVED,
+ CS_BGR32 = 1<<1 | CS_BGR | CS_INTERLEAVED,
+ CS_YUY2 = 1<<2 | CS_YUV | CS_INTERLEAVED,
+ CS_YV12 = 1<<3 | CS_YUV | CS_PLANAR, // y-v-u, planar
+ CS_I420 = 1<<4 | CS_YUV | CS_PLANAR, // y-u-v, planar
+ CS_IYUV = 1<<4 | CS_YUV | CS_PLANAR // same as above
+ };
+ int pixel_type; // changed to int as of 2.5
+
+
+ int audio_samples_per_second; // 0 means no audio
+ int sample_type; // as of 2.5
+ __int64 num_audio_samples; // changed as of 2.5
+ int nchannels; // as of 2.5
+
+ // Imagetype properties
+
+ int image_type;
+
+ enum {
+ IT_BFF = 1<<0,
+ IT_TFF = 1<<1,
+ IT_FIELDBASED = 1<<2
+ };
+
+ // useful functions of the above
+ bool HasVideo() const { return (width!=0); }
+ bool HasAudio() const { return (audio_samples_per_second!=0); }
+ bool IsRGB() const { return !!(pixel_type&CS_BGR); }
+ bool IsRGB24() const { return (pixel_type&CS_BGR24)==CS_BGR24; } // Clear out additional properties
+ bool IsRGB32() const { return (pixel_type & CS_BGR32) == CS_BGR32 ; }
+ bool IsYUV() const { return !!(pixel_type&CS_YUV ); }
+ bool IsYUY2() const { return (pixel_type & CS_YUY2) == CS_YUY2; }
+ bool IsYV12() const { return ((pixel_type & CS_YV12) == CS_YV12)||((pixel_type & CS_I420) == CS_I420); }
+ bool IsColorSpace(int c_space) const { return ((pixel_type & c_space) == c_space); }
+ bool Is(int property) const { return ((pixel_type & property)==property ); }
+ bool IsPlanar() const { return !!(pixel_type & CS_PLANAR); }
+ bool IsFieldBased() const { return !!(image_type & IT_FIELDBASED); }
+ bool IsParityKnown() const { return ((image_type & IT_FIELDBASED)&&(image_type & (IT_BFF|IT_TFF))); }
+ bool IsBFF() const { return !!(image_type & IT_BFF); }
+ bool IsTFF() const { return !!(image_type & IT_TFF); }
+
+ bool IsVPlaneFirst() const {return ((pixel_type & CS_YV12) == CS_YV12); } // Don't use this
+ int BytesFromPixels(int pixels) const { return pixels * (BitsPerPixel()>>3); } // Will not work on planar images, but will return only luma planes
+ int RowSize() const { return BytesFromPixels(width); } // Also only returns first plane on planar images
+ int BMPSize() const { if (IsPlanar()) {int p = height * ((RowSize()+3) & ~3); p+=p>>1; return p; } return height * ((RowSize()+3) & ~3); }
+ __int64 AudioSamplesFromFrames(__int64 frames) const { return (fps_numerator && HasVideo()) ? ((__int64)(frames) * audio_samples_per_second * fps_denominator / fps_numerator) : 0; }
+ int FramesFromAudioSamples(__int64 samples) const { return (fps_denominator && HasAudio()) ? (int)((samples * (__int64)fps_numerator)/((__int64)fps_denominator * (__int64)audio_samples_per_second)) : 0; }
+ __int64 AudioSamplesFromBytes(__int64 bytes) const { return HasAudio() ? bytes / BytesPerAudioSample() : 0; }
+ __int64 BytesFromAudioSamples(__int64 samples) const { return samples * BytesPerAudioSample(); }
+ int AudioChannels() const { return nchannels; }
+ int SampleType() const{ return sample_type;}
+ bool IsSampleType(int testtype) const{ return !!(sample_type&testtype);}
+ int SamplesPerSecond() const { return audio_samples_per_second; }
+ int BytesPerAudioSample() const { return nchannels*BytesPerChannelSample();}
+ void SetFieldBased(bool isfieldbased) { if (isfieldbased) image_type|=IT_FIELDBASED; else image_type&=~IT_FIELDBASED; }
+ void Set(int property) { image_type|=property; }
+ void Clear(int property) { image_type&=~property; }
+
+ int BitsPerPixel() const {
+ switch (pixel_type) {
+ case CS_BGR24:
+ return 24;
+ case CS_BGR32:
+ return 32;
+ case CS_YUY2:
+ return 16;
+ case CS_YV12:
+ case CS_I420:
+ return 12;
+ default:
+ return 0;
+ }
+ }
+ int BytesPerChannelSample() const {
+ switch (sample_type) {
+ case SAMPLE_INT8:
+ return sizeof(signed char);
+ case SAMPLE_INT16:
+ return sizeof(signed short);
+ case SAMPLE_INT24:
+ return 3;
+ case SAMPLE_INT32:
+ return sizeof(signed int);
+ case SAMPLE_FLOAT:
+ return sizeof(SFLOAT);
+ default:
+ _ASSERTE("Sample type not recognized!");
+ return 0;
+ }
+ }
+
+ // useful mutator
+ void SetFPS(unsigned numerator, unsigned denominator) {
+ if ((numerator == 0) || (denominator == 0)) {
+ fps_numerator = 0;
+ fps_denominator = 1;
+ }
+ else {
+ unsigned x=numerator, y=denominator;
+ while (y) { // find gcd
+ unsigned t = x%y; x = y; y = t;
+ }
+ fps_numerator = numerator/x;
+ fps_denominator = denominator/x;
+ }
+ }
+
+ // Range protected multiply-divide of FPS
+ void MulDivFPS(unsigned multiplier, unsigned divisor) {
+ unsigned __int64 numerator = UInt32x32To64(fps_numerator, multiplier);
+ unsigned __int64 denominator = UInt32x32To64(fps_denominator, divisor);
+
+ unsigned __int64 x=numerator, y=denominator;
+ while (y) { // find gcd
+ unsigned __int64 t = x%y; x = y; y = t;
+ }
+ numerator /= x; // normalize
+ denominator /= x;
+
+ unsigned __int64 temp = numerator | denominator; // Just looking top bit
+ unsigned u = 0;
+#ifdef __GNUC__
+ while (temp & 0xffffffff80000000LL) { // or perhaps > 16777216*2
+#else
+ while (temp & 0xffffffff80000000) { // or perhaps > 16777216*2
+#endif
+ temp = Int64ShrlMod32(temp, 1);
+ u++;
+ }
+ if (u) { // Scale to fit
+ const unsigned round = 1 << (u-1);
+ SetFPS( (unsigned)Int64ShrlMod32(numerator + round, u),
+ (unsigned)Int64ShrlMod32(denominator + round, u) );
+ }
+ else {
+ fps_numerator = (unsigned)numerator;
+ fps_denominator = (unsigned)denominator;
+ }
+ }
+
+ // Test for same colorspace
+ bool IsSameColorspace(const VideoInfo& vi) const {
+ if (vi.pixel_type == pixel_type) return TRUE;
+ if (IsYV12() && vi.IsYV12()) return TRUE;
+ return FALSE;
+ }
+
+};
+
+
+
+
+// VideoFrameBuffer holds information about a memory block which is used
+// for video data. For efficiency, instances of this class are not deleted
+// when the refcount reaches zero; instead they're stored in a linked list
+// to be reused. The instances are deleted when the corresponding AVS
+// file is closed.
+
+class VideoFrameBuffer {
+ BYTE* const data;
+ const int data_size;
+ // sequence_number is incremented every time the buffer is changed, so
+ // that stale views can tell they're no longer valid.
+ long sequence_number;
+
+ friend class VideoFrame;
+ friend class Cache;
+ friend class ScriptEnvironment;
+ long refcount;
+
+public:
+ VideoFrameBuffer(int size);
+ VideoFrameBuffer();
+ ~VideoFrameBuffer();
+
+ const BYTE* GetReadPtr() const { return data; }
+ BYTE* GetWritePtr() { ++sequence_number; return data; }
+ int GetDataSize() { return data_size; }
+ int GetSequenceNumber() { return sequence_number; }
+ int GetRefcount() { return refcount; }
+};
+
+
+class IClip;
+class PClip;
+class PVideoFrame;
+class IScriptEnvironment;
+class AVSValue;
+
+
+// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new
+// is overloaded to recycle class instances.
+
+class VideoFrame {
+ int refcount;
+ VideoFrameBuffer* const vfb;
+ const int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture.
+
+ friend class PVideoFrame;
+ void AddRef() { InterlockedIncrement((long *)&refcount); }
+ void Release() { if (refcount==1) InterlockedDecrement(&vfb->refcount); InterlockedDecrement((long *)&refcount); }
+
+ friend class ScriptEnvironment;
+ friend class Cache;
+
+ VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height);
+ VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV);
+
+ void* operator new(size_t size);
+// TESTME: OFFSET U/V may be switched to what could be expected from AVI standard!
+public:
+ int GetPitch() const { return pitch; }
+ int GetPitch(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: return pitchUV;} return pitch; }
+ int GetRowSize() const { return row_size; }
+ int GetRowSize(int plane) const {
+ switch (plane) {
+ case PLANAR_U: case PLANAR_V: if (pitchUV) return row_size>>1; else return 0;
+ case PLANAR_U_ALIGNED: case PLANAR_V_ALIGNED:
+ if (pitchUV) {
+ int r = ((row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)) )>>1; // Aligned rowsize
+ if (r<=pitchUV)
+ return r;
+ return row_size>>1;
+ } else return 0;
+ case PLANAR_Y_ALIGNED:
+ int r = (row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)); // Aligned rowsize
+ if (r<=pitch)
+ return r;
+ return row_size;
+ }
+ return row_size; }
+ int GetHeight() const { return height; }
+ int GetHeight(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: if (pitchUV) return height>>1; return 0;} return height; }
+
+ // generally you shouldn't use these three
+ VideoFrameBuffer* GetFrameBuffer() const { return vfb; }
+ int GetOffset() const { return offset; }
+ int GetOffset(int plane) const { switch (plane) {case PLANAR_U: return offsetU;case PLANAR_V: return offsetV;default: return offset;}; }
+
+ // in plugins use env->SubFrame()
+ VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const;
+ VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV) const;
+
+
+ const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; }
+ const BYTE* GetReadPtr(int plane) const { return vfb->GetReadPtr() + GetOffset(plane); }
+
+ bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); }
+
+ BYTE* GetWritePtr() const {
+ if (vfb->GetRefcount()>1) {
+ _ASSERT(FALSE);
+ //throw AvisynthError("Internal Error - refcount was more than one!");
+ }
+ return IsWritable() ? (vfb->GetWritePtr() + offset) : 0;
+ }
+
+ BYTE* GetWritePtr(int plane) const {
+ if (plane==PLANAR_Y) {
+ if (vfb->GetRefcount()>1) {
+ _ASSERT(FALSE);
+// throw AvisynthError("Internal Error - refcount was more than one!");
+ }
+ return IsWritable() ? vfb->GetWritePtr() + GetOffset(plane) : 0;
+ }
+ return vfb->data + GetOffset(plane);
+ }
+
+ ~VideoFrame() { InterlockedDecrement(&vfb->refcount); }
+};
+
+enum {
+ CACHE_NOTHING=0,
+ CACHE_RANGE=1,
+ CACHE_ALL=2,
+ CACHE_AUDIO=3,
+ CACHE_AUDIO_NONE=4
+ };
+
+// Base class for all filters.
+class IClip {
+ friend class PClip;
+ friend class AVSValue;
+ int refcnt;
+ void AddRef() { InterlockedIncrement((long *)&refcnt); }
+ void Release() { InterlockedDecrement((long *)&refcnt); if (!refcnt) delete this; }
+public:
+ IClip() : refcnt(0) {}
+
+ virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; }
+
+ virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0;
+ virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame
+ virtual void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) = 0; // start and count are in samples
+ virtual void __stdcall SetCacheHints(int cachehints,int frame_range) = 0 ; // We do not pass cache requests upwards, only to the next filter.
+ virtual const VideoInfo& __stdcall GetVideoInfo() = 0;
+ virtual __stdcall ~IClip() {}
+};
+
+
+// smart pointer to IClip
+class PClip {
+
+ IClip* p;
+
+ IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; }
+ friend class AVSValue;
+ friend class VideoFrame;
+
+ void Init(IClip* x) {
+ if (x) x->AddRef();
+ p=x;
+ }
+ void Set(IClip* x) {
+ if (x) x->AddRef();
+ if (p) p->Release();
+ p=x;
+ }
+
+public:
+ PClip() { p = 0; }
+ PClip(const PClip& x) { Init(x.p); }
+ PClip(IClip* x) { Init(x); }
+ void operator=(IClip* x) { Set(x); }
+ void operator=(const PClip& x) { Set(x.p); }
+
+ IClip* operator->() const { return p; }
+
+ // useful in conditional expressions
+ operator void*() const { return p; }
+ bool operator!() const { return !p; }
+
+ ~PClip() { if (p) p->Release(); }
+};
+
+
+// smart pointer to VideoFrame
+class PVideoFrame {
+
+ VideoFrame* p;
+
+ void Init(VideoFrame* x) {
+ if (x) x->AddRef();
+ p=x;
+ }
+ void Set(VideoFrame* x) {
+ if (x) x->AddRef();
+ if (p) p->Release();
+ p=x;
+ }
+
+public:
+ PVideoFrame() { p = 0; }
+ PVideoFrame(const PVideoFrame& x) { Init(x.p); }
+ PVideoFrame(VideoFrame* x) { Init(x); }
+ void operator=(VideoFrame* x) { Set(x); }
+ void operator=(const PVideoFrame& x) { Set(x.p); }
+
+ VideoFrame* operator->() const { return p; }
+
+ // for conditional expressions
+ operator void*() const { return p; }
+ bool operator!() const { return !p; }
+
+ ~PVideoFrame() { if (p) p->Release();}
+};
+
+
+class AVSValue {
+public:
+
+ AVSValue() { type = 'v'; }
+ AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); }
+ AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); }
+ AVSValue(bool b) { type = 'b'; boolean = b; }
+ AVSValue(int i) { type = 'i'; integer = i; }
+// AVSValue(__int64 l) { type = 'l'; longlong = l; }
+ AVSValue(float f) { type = 'f'; floating_pt = f; }
+ AVSValue(double f) { type = 'f'; floating_pt = float(f); }
+ AVSValue(const char* s) { type = 's'; string = s; }
+ AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; }
+ AVSValue(const AVSValue& v) { Assign(&v, true); }
+
+ ~AVSValue() { if (IsClip() && clip) clip->Release(); }
+ AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; }
+
+ // Note that we transparently allow 'int' to be treated as 'float'.
+ // There are no int<->bool conversions, though.
+
+ bool Defined() const { return type != 'v'; }
+ bool IsClip() const { return type == 'c'; }
+ bool IsBool() const { return type == 'b'; }
+ bool IsInt() const { return type == 'i'; }
+// bool IsLong() const { return (type == 'l'|| type == 'i'); }
+ bool IsFloat() const { return type == 'f' || type == 'i'; }
+ bool IsString() const { return type == 's'; }
+ bool IsArray() const { return type == 'a'; }
+
+ PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; }
+ bool AsBool() const { _ASSERTE(IsBool()); return boolean; }
+ int AsInt() const { _ASSERTE(IsInt()); return integer; }
+// int AsLong() const { _ASSERTE(IsLong()); return longlong; }
+ const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; }
+ double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; }
+
+ bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; }
+ int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; }
+ double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; }
+ const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; }
+
+ int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; }
+
+ const AVSValue& operator[](int index) const {
+ _ASSERTE(IsArray() && index>=0 && index=0 && indexIsClip() && src->clip)
+ src->clip->AddRef();
+ if (!init && IsClip() && clip)
+ clip->Release();
+ // make sure this copies the whole struct!
+ ((__int32*)this)[0] = ((__int32*)src)[0];
+ ((__int32*)this)[1] = ((__int32*)src)[1];
+ }
+};
+
+
+// instantiable null filter
+class GenericVideoFilter : public IClip {
+protected:
+ PClip child;
+ VideoInfo vi;
+public:
+ GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); }
+ PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); }
+ void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); }
+ const VideoInfo& __stdcall GetVideoInfo() { return vi; }
+ bool __stdcall GetParity(int n) { return child->GetParity(n); }
+ void __stdcall SetCacheHints(int cachehints,int frame_range) { } ; // We do not pass cache requests upwards, only to the next filter.
+};
+
+
+class AvisynthError /* exception */ {
+public:
+ const char* const msg;
+ AvisynthError(const char* _msg) : msg(_msg) {}
+};
+
+
+
+
+/* Helper classes useful to plugin authors */
+
+class AlignPlanar : public GenericVideoFilter
+{
+public:
+ AlignPlanar(PClip _clip);
+ static PClip Create(PClip clip);
+ PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
+};
+
+
+
+class FillBorder : public GenericVideoFilter
+{
+public:
+ FillBorder(PClip _clip);
+ static PClip Create(PClip clip);
+ PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
+};
+
+
+
+class ConvertAudio : public GenericVideoFilter
+/**
+ * Helper class to convert audio to any format
+ **/
+{
+public:
+ ConvertAudio(PClip _clip, int prefered_format);
+ void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env);
+ void __stdcall SetCacheHints(int cachehints,int frame_range); // We do pass cache requests upwards, to the cache!
+
+ static PClip Create(PClip clip, int sample_type, int prefered_type);
+ static AVSValue __cdecl Create_float(AVSValue args, void*, IScriptEnvironment*);
+ static AVSValue __cdecl Create_32bit(AVSValue args, void*, IScriptEnvironment*);
+ static AVSValue __cdecl Create_24bit(AVSValue args, void*, IScriptEnvironment*);
+ static AVSValue __cdecl Create_16bit(AVSValue args, void*, IScriptEnvironment*);
+ static AVSValue __cdecl Create_8bit(AVSValue args, void*, IScriptEnvironment*);
+ virtual ~ConvertAudio();
+
+private:
+ void convertToFloat(char* inbuf, float* outbuf, char sample_type, int count);
+ void convertToFloat_3DN(char* inbuf, float* outbuf, char sample_type, int count);
+ void convertToFloat_SSE(char* inbuf, float* outbuf, char sample_type, int count);
+ void convertToFloat_SSE2(char* inbuf, float* outbuf, char sample_type, int count);
+ void convertFromFloat(float* inbuf, void* outbuf, char sample_type, int count);
+ void convertFromFloat_3DN(float* inbuf, void* outbuf, char sample_type, int count);
+ void convertFromFloat_SSE(float* inbuf, void* outbuf, char sample_type, int count);
+ void convertFromFloat_SSE2(float* inbuf, void* outbuf, char sample_type, int count);
+
+ __inline int Saturate_int8(float n);
+ __inline short Saturate_int16(float n);
+ __inline int Saturate_int24(float n);
+ __inline int Saturate_int32(float n);
+
+ char src_format;
+ char dst_format;
+ int src_bps;
+ char *tempbuffer;
+ SFLOAT *floatbuffer;
+ int tempbuffer_size;
+};
+
+
+// For GetCPUFlags. These are backwards-compatible with those in VirtualDub.
+enum {
+ /* slowest CPU to support extension */
+ CPUF_FORCE = 0x01, // N/A
+ CPUF_FPU = 0x02, // 386/486DX
+ CPUF_MMX = 0x04, // P55C, K6, PII
+ CPUF_INTEGER_SSE = 0x08, // PIII, Athlon
+ CPUF_SSE = 0x10, // PIII, Athlon XP/MP
+ CPUF_SSE2 = 0x20, // PIV, Hammer
+ CPUF_3DNOW = 0x40, // K6-2
+ CPUF_3DNOW_EXT = 0x80, // Athlon
+ CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which only Hammer
+ // will have anyway)
+ CPUF_SSE3 = 0x100, // Some P4 & Athlon 64.
+};
+#define MAX_INT 0x7fffffff
+#define MIN_INT -0x7fffffff
+
+
+
+class IScriptEnvironment {
+public:
+ virtual __stdcall ~IScriptEnvironment() {}
+
+ virtual /*static*/ long __stdcall GetCPUFlags() = 0;
+
+ virtual char* __stdcall SaveString(const char* s, int length = -1) = 0;
+ virtual char* __stdcall Sprintf(const char* fmt, ...) = 0;
+ // note: val is really a va_list; I hope everyone typedefs va_list to a pointer
+ virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0;
+
+ __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0;
+
+ class NotFound /*exception*/ {}; // thrown by Invoke and GetVar
+
+ typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env);
+
+ virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0;
+ virtual bool __stdcall FunctionExists(const char* name) = 0;
+ virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0;
+
+ virtual AVSValue __stdcall GetVar(const char* name) = 0;
+ virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0;
+ virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0;
+
+ virtual void __stdcall PushContext(int level=0) = 0;
+ virtual void __stdcall PopContext() = 0;
+
+ // align should be 4 or 8
+ virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=FRAME_ALIGN) = 0;
+
+ virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0;
+
+ virtual /*static*/ void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0;
+
+ typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env);
+ virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0;
+
+ virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0;
+
+ virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0;
+
+ virtual int __stdcall SetMemoryMax(int mem) = 0;
+
+ virtual int __stdcall SetWorkingDir(const char * newdir) = 0;
+
+ virtual void* __stdcall ManageCache(int key, void* data) = 0;
+
+ enum PlanarChromaAlignmentMode {
+ PlanarChromaAlignmentOff,
+ PlanarChromaAlignmentOn,
+ PlanarChromaAlignmentTest };
+
+ virtual bool __stdcall PlanarChromaAlignment(PlanarChromaAlignmentMode key) = 0;
+
+ virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0;
+};
+
+
+// avisynth.dll exports this; it's a way to use it as a library, without
+// writing an AVS script or without going through AVIFile.
+IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION);
+
+
+#pragma pack(pop)
+
+#endif //__AVISYNTH_H__
diff --git a/csri/frontends/cmdline/Makefile.am b/csri/frontends/cmdline/Makefile.am
new file mode 100644
index 000000000..10a384563
--- /dev/null
+++ b/csri/frontends/cmdline/Makefile.am
@@ -0,0 +1,6 @@
+bin_PROGRAMS = csri
+AM_CPPFLAGS = -I$(top_srcdir)/include
+csri_SOURCES = cmdmain.c render.c
+csri_LDADD = ../../lib/libcsri.la
+
+noinst_HEADERS = render.h
diff --git a/csri/frontends/cmdline/cmdmain.c b/csri/frontends/cmdline/cmdmain.c
new file mode 100644
index 000000000..5b1d47196
--- /dev/null
+++ b/csri/frontends/cmdline/cmdmain.c
@@ -0,0 +1,473 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "acconf.h"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "render.h"
+
+csri_rend *r;
+
+static int do_usage(FILE *fd)
+{
+ fprintf(fd, "usage: csri [COMMON-OPTIONS] COMMAND [COMMAND-OPTIONS]\n"
+ "\n"
+ "common options: [-r renderer [-s specific]]\n"
+ "\t-r\tselect a renderer, by name\n"
+ "\t-s\tselect a renderer version, by specific name\n"
+ "\n"
+ "commands:\n"
+ "\tlist\tshow installed renderers\n"
+ "\tinfo\tshow detailed renderer information\n"
+ "\trender\trender subtitle output\n"
+#ifdef HAVE_LIBPNG
+ "\t\t-i FILE\t\tread background from PNG file\n"
+ "\t\t-o PREFIX\twrite output to PREFIX_nnnn.png\n"
+#endif
+ "\t\t-A\t\tkeep alpha\n"
+ "\t\t-t [start][:[end][:[step]]]\tspecify timestamps to be rendered\n"
+ "\t\tSUBFILE\t\tsubtitle file to load\n"
+ "\n");
+ return 2;
+}
+
+static int do_list(int argc, char **argv)
+{
+ unsigned num = 0;
+
+ if (argc)
+ return do_usage(stderr);
+
+ while (r) {
+ struct csri_info *info = csri_renderer_info(r);
+ if (!info)
+ continue;
+ printf("%s:%s %s, %s, %s\n", info->name, info->specific,
+ info->longname, info->author, info->copyright);
+ r = csri_renderer_next(r);
+ num++;
+ }
+ fprintf(stderr, "%u renderers found\n", num);
+ return num > 0 ? 0 : 1;
+}
+
+static csri_ext_id known_exts[] = {
+ CSRI_EXT_OPENERR,
+ CSRI_EXT_LOGGING,
+ CSRI_EXT_STREAM,
+ CSRI_EXT_STREAM_ASS,
+ CSRI_EXT_STREAM_TEXT,
+ CSRI_EXT_STREAM_DISCARD,
+ NULL
+};
+
+static const char *dummy_script = "[Script Info]\r\n"
+ "ScriptType: v4.00\r\n"
+ "[V4 Styles]\r\n"
+ "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, "
+ "TertiaryColour, BackColour, Bold, Italic, BorderStyle, "
+ "Outline, Shadow, Alignment, MarginL, MarginR, MarginV, "
+ "AlphaLevel, Encoding\r\n"
+ "Style: Default,Arial,20,&HFFFFFF&,&H00FFFF&,&H000000&,&H000000&,"
+ "0,0,1,2,2,2,10,10,10,0,0\r\n"
+ "[Events]\r\n"
+ "Format: Marked, Start, End, Style, Name, "
+ "MarginL, MarginR, MarginV, Effect, Text\r\n"
+ "Dialogue: Marked=0,0:00:01.00,0:00:02.00,Default,,0000,0000,0000,,"
+ "test\r\n";
+
+static const char *dummy_stream = "1,0,Default,,0000,0000,0000,,stream\r\n";
+
+#define e(x) { #x, CSRI_F_ ## x }
+#define ree(x) e(RGB ## x), e(x ## RGB), e(BGR ## x), e(x ## BGR)
+static struct csri_fmtlistent {
+ const char *label;
+ enum csri_pixfmt fmt;
+} csri_fmts[] = {
+ ree(A), ree(_),
+ e(RGB), e(BGR),
+ e(AYUV), e(YUVA), e(YVUA), e(YUY2), e(YV12A), e(YV12),
+ { NULL, 0 }
+};
+
+static void listfmts()
+{
+ csri_inst *i;
+ struct csri_fmtlistent *fmt;
+ struct csri_fmt f;
+
+ printf("\ntrying to get list of supported colorspaces:\n");
+ fflush(stdout);
+ i = csri_open_mem(r, dummy_script, strlen(dummy_script), NULL);
+
+ f.width = f.height = 256;
+ for (fmt = csri_fmts; fmt->label; fmt++) {
+ f.pixfmt = fmt->fmt;
+ if (!csri_request_fmt(i, &f))
+ printf("\t[%04x] %s\n", fmt->fmt, fmt->label);
+ }
+ csri_close(i);
+}
+
+static int do_info(int argc, char **argv)
+{
+ struct csri_info *info;
+ csri_ext_id *id;
+ if (argc)
+ return do_usage(stderr);
+
+ info = csri_renderer_info(r);
+ if (!info)
+ return 1;
+ printf("%s:%s\n\t%s\n\t%s\n\t%s\n", info->name, info->specific,
+ info->longname, info->author, info->copyright);
+ printf("supported CSRI extensions:\n");
+ for (id = known_exts; *id; id++) {
+ void *rext = csri_query_ext(r, *id);
+ void *lext = csri_query_ext(NULL, *id);
+ if (lext || rext) {
+ printf("\t%s ", *id);
+ if (!lext)
+ printf("\n");
+ else if (!rext)
+ printf("[library only]\n");
+ else if (rext == lext)
+ printf("[emulated by library]\n");
+ else
+ printf("\n");
+ }
+ }
+ listfmts();
+ return 0;
+}
+
+static void logfunc(void *appdata, enum csri_logging_severity sev,
+ const char *message)
+{
+ char severity[32];
+ switch (sev) {
+ case CSRI_LOG_DEBUG: strcpy(severity, "[debug]"); break;
+ case CSRI_LOG_INFO: strcpy(severity, "[info]"); break;
+ case CSRI_LOG_NOTICE: strcpy(severity, "[notice]"); break;
+ case CSRI_LOG_WARNING: strcpy(severity, "[warning]"); break;
+ case CSRI_LOG_ERROR: strcpy(severity, "[error]"); break;
+ default: snprintf(severity, 32, "[%d?]", (int)sev);
+ }
+ fprintf(stderr, "%-10s %s\n", severity, message);
+}
+
+static int real_render(double *times, const char *infile, const char *outfile,
+ const char *script, enum csri_pixfmt pfmt)
+{
+ struct csri_frame *bg, *a;
+ csri_inst *inst;
+ struct csri_fmt fmt;
+ double now;
+ int idx;
+ uint32_t width = 640, height = 480;
+
+ bg = infile ? png_load(infile, &width, &height, pfmt)
+ : frame_alloc(width, height, pfmt);
+ a = frame_alloc(width, height, pfmt);
+ if (!bg || !a) {
+ fprintf(stderr, "failed to allocate frame\n");
+ if (!bg)
+ fprintf(stderr, "\t- problem with background.\n");
+ return 2;
+ }
+ inst = csri_open_file(r, script, NULL);
+ if (!inst) {
+ fprintf(stderr, "failed to open script \"%s\"\n", script);
+ return 2;
+ }
+ fmt.pixfmt = pfmt;
+ fmt.width = width;
+ fmt.height = height;
+ if (csri_request_fmt(inst, &fmt)) {
+ fprintf(stderr, "format not supported by renderer\n");
+ return 2;
+ }
+
+ idx = 0;
+ for (now = times[0]; now <= times[1]; now += times[2]) {
+ frame_copy(a, bg, width, height);
+ csri_render(inst, a, now);
+ if (outfile) {
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer),
+ "%s_%04d.png", outfile, idx);
+ printf("%s\n", buffer);
+ png_store(a, buffer, width, height);
+ }
+ idx++;
+ }
+ csri_close(inst);
+ inst = NULL;
+ frame_free(bg);
+ frame_free(a);
+ return 0;
+}
+
+static int do_render(int argc, char **argv)
+{
+ double times[3] = {0.0, 0.0, 1.0};
+ const char *outfile = NULL, *infile = NULL;
+ struct csri_fmtlistent *fmte;
+ int keepalpha = 0;
+ enum csri_pixfmt fmt = ~0U;
+ argv--, argc++;
+ while (1) {
+ int c, i;
+ const char *short_options = "t:o:i:F:A";
+ char *arg, *end, *err;
+ struct option long_options[] = {
+ {"time", 1, 0, 't'},
+ {"output", 1, 0, 'o'},
+ {"input", 1, 0, 'i'},
+ {"format", 0, 0, 'F'},
+ {"alpha", 0, 0, 'A'},
+ {0, 0, 0, 0}
+ };
+ c = getopt_long(argc, argv, short_options, long_options, NULL);
+ if (c == -1)
+ break;
+ switch (c) {
+ case 't':
+ arg = optarg;
+ for (i = 0; i < 3; i++) {
+ end = strchr(arg, ':');
+ if (end)
+ *end = '\0';
+ if (*arg) {
+ times[i] = strtod(arg, &err);
+ if (*err) {
+ fprintf(stderr,
+ "invalid time: %s\n",
+ arg);
+ return do_usage(stderr);
+ }
+ }
+ if (!end)
+ break;
+ arg = end + 1;
+ }
+ break;
+ case 'i':
+ infile = optarg;
+ break;
+ case 'o':
+ outfile = optarg;
+ break;
+ case 'A':
+ if (fmt != ~0U)
+ return do_usage(stderr);
+ keepalpha = 1;
+ break;
+ case 'F':
+ if (keepalpha || fmt != ~0U)
+ return do_usage(stderr);
+ for (fmte = csri_fmts; fmte->label; fmte++)
+ if (!strcmp(fmte->label, optarg))
+ break;
+ if (!fmte->label)
+ return do_usage(stderr);
+ fmt = fmte->fmt;
+ break;
+ default:
+ return do_usage(stderr);
+ };
+ }
+ if (fmt == ~0U)
+ fmt = keepalpha ? CSRI_F_RGBA : CSRI_F_RGB_;
+ if (!isfinite(times[0])) {
+ fprintf(stderr, "invalid start time\n");
+ return do_usage(stderr);
+ }
+ if (!isfinite(times[1]) || times[1] < times[0]) {
+ fprintf(stderr, "invalid end time\n");
+ return do_usage(stderr);
+ }
+ if (!isnormal(times[2]) || times[2] < 0.0) {
+ fprintf(stderr, "invalid end time\n");
+ return do_usage(stderr);
+ }
+ if (argc - optind != 1) {
+ fprintf(stderr, "script name missing\n");
+ return do_usage(stderr);
+ }
+ return real_render(times, infile, outfile, argv[optind], fmt);
+}
+
+static int do_streamtest(int argc, char **argv)
+{
+ const char *outfile = NULL;
+ struct csri_fmtlistent *fmte;
+ enum csri_pixfmt pfmt = ~0U;
+ struct csri_frame *bg, *a;
+ csri_inst *inst;
+ struct csri_fmt fmt;
+ uint32_t width = 640, height = 480;
+ struct csri_stream_ext *sext;
+
+ argv--, argc++;
+ while (1) {
+ int c;
+ const char *short_options = "o:F:";
+ struct option long_options[] = {
+ {"output", 1, 0, 'o'},
+ {"format", 0, 0, 'F'},
+ {0, 0, 0, 0}
+ };
+ c = getopt_long(argc, argv, short_options, long_options, NULL);
+ if (c == -1)
+ break;
+ switch (c) {
+ case 'o':
+ outfile = optarg;
+ break;
+ case 'F':
+ if (pfmt != ~0U)
+ return do_usage(stderr);
+ for (fmte = csri_fmts; fmte->label; fmte++)
+ if (!strcmp(fmte->label, optarg))
+ break;
+ if (!fmte->label)
+ return do_usage(stderr);
+ pfmt = fmte->fmt;
+ break;
+ default:
+ return do_usage(stderr);
+ };
+ }
+ if (pfmt == ~0U)
+ pfmt = CSRI_F_RGB_;
+
+ sext = (struct csri_stream_ext *)csri_query_ext(r,
+ CSRI_EXT_STREAM_ASS);
+ if (!sext) {
+ fprintf(stderr, "renderer does not support ASS streaming\n");
+ return 2;
+ }
+
+ bg = frame_alloc(width, height, pfmt);
+ a = frame_alloc(width, height, pfmt);
+ if (!bg || !a) {
+ fprintf(stderr, "failed to allocate frame\n");
+ return 2;
+ }
+ inst = sext->init_stream(r, dummy_script, strlen(dummy_script), NULL);
+ if (!inst) {
+ fprintf(stderr, "failed to initialize stream\n");
+ return 2;
+ }
+ fmt.pixfmt = pfmt;
+ fmt.width = width;
+ fmt.height = height;
+ if (csri_request_fmt(inst, &fmt)) {
+ fprintf(stderr, "format not supported by renderer\n");
+ return 2;
+ }
+
+ frame_copy(a, bg, width, height);
+ csri_render(inst, a, 1.75);
+ if (outfile) {
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer),
+ "%s_nstream.png", outfile);
+ printf("%s\n", buffer);
+ png_store(a, buffer, width, height);
+ }
+
+ frame_copy(a, bg, width, height);
+ sext->push_packet(inst, dummy_stream, strlen(dummy_stream),
+ 1.5, 2.0);
+ csri_render(inst, a, 1.75);
+ if (outfile) {
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer),
+ "%s_stream.png", outfile);
+ printf("%s\n", buffer);
+ png_store(a, buffer, width, height);
+ }
+
+ csri_close(inst);
+ inst = NULL;
+ frame_free(bg);
+ frame_free(a);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ struct csri_logging_ext *logext;
+
+ if (argc < 2)
+ return do_usage(stderr);
+
+ logext = (struct csri_logging_ext *)csri_query_ext(NULL,
+ CSRI_EXT_LOGGING);
+ if (logext && logext->set_logcallback)
+ logext->set_logcallback(logfunc, NULL);
+ else
+ fprintf(stderr, "warning: unable to set log callback\n");
+
+ r = csri_renderer_default();
+ argc--, argv++;
+ if (!strcmp(argv[0], "list"))
+ return do_list(argc - 1, argv + 1);
+ if (!strcmp(argv[0], "-r")) {
+ const char *name = NULL, *spec = NULL;
+ if (argc < 2)
+ return do_usage(stderr);
+ name = argv[1];
+ argc -= 2, argv += 2;
+ if (!strcmp(argv[0], "-s")) {
+ if (argc < 2)
+ return do_usage(stderr);
+ spec = argv[1];
+ }
+ r = csri_renderer_byname(name, spec);
+ if (!r) {
+ fprintf(stderr, "renderer %s:%s not found.\n",
+ name, spec ? spec : "*");
+ return 2;
+ }
+ }
+ if (!strcmp(argv[0], "info"))
+ return do_info(argc - 1, argv + 1);
+ if (!strcmp(argv[0], "render"))
+ return do_render(argc - 1, argv + 1);
+ if (!strcmp(argv[0], "streamtest"))
+ return do_streamtest(argc - 1, argv + 1);
+ return do_usage(stderr);
+}
diff --git a/csri/frontends/cmdline/render.c b/csri/frontends/cmdline/render.c
new file mode 100644
index 000000000..87b205ace
--- /dev/null
+++ b/csri/frontends/cmdline/render.c
@@ -0,0 +1,240 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "acconf.h"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "render.h"
+
+extern csri_rend *r;
+
+#ifdef HAVE_LIBPNG
+#include
+
+struct csri_frame *png_load(const char *filename,
+ uint32_t *width, uint32_t *height, enum csri_pixfmt fmt)
+{
+ struct csri_frame *frame;
+ int bit_depth, color_type;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_bytep *rows;
+ unsigned char *imgdata;
+ FILE *fp;
+
+ if (!csri_is_rgb(fmt)) {
+ fprintf(stderr, "PNG loader: can't load non-RGB.\n");
+ return NULL;
+ }
+
+ frame = (struct csri_frame *)malloc(sizeof(struct csri_frame));
+ if (!frame)
+ return NULL;
+ memset(frame, 0, sizeof(*frame));
+ frame->pixfmt = fmt;
+
+ fp = fopen(filename, "rb");
+ if (!fp) {
+ fprintf(stderr, "Error opening \"%s\": %s (%d)\n",
+ filename, strerror(errno), errno);
+ return NULL;
+ }
+
+ assert(png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ NULL, NULL, NULL));
+ assert(info_ptr = png_create_info_struct(png_ptr));
+ //keepalpha ? CSRI_F_RGBA : CSRI_F_RGB_;
+
+ png_init_io(png_ptr, fp);
+ png_read_info(png_ptr, info_ptr);
+ png_get_IHDR(png_ptr, info_ptr,
+ (png_uint_32 *)width, (png_uint_32 *)height,
+ &bit_depth, &color_type, NULL, NULL, NULL);
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb(png_ptr);
+ if (bit_depth < 8)
+ png_set_packing(png_ptr);
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha(png_ptr);
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+ if ((fmt < 0x200 && (fmt & 2)) || fmt == CSRI_F_BGR)
+ png_set_bgr(png_ptr);
+ if (csri_has_alpha(fmt)) {
+ int before = fmt == CSRI_F_ARGB || fmt == CSRI_F_ABGR;
+ if (color_type == PNG_COLOR_TYPE_RGB)
+ png_set_filler(png_ptr, 0xff, before
+ ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
+ else {
+ png_set_invert_alpha(png_ptr);
+ if (before)
+ png_set_swap_alpha(png_ptr);
+ }
+ } else {
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ png_set_strip_alpha(png_ptr);
+ if (fmt != CSRI_F_RGB && fmt != CSRI_F_BGR) {
+ int before = fmt == CSRI_F__RGB || fmt == CSRI_F__BGR;
+ png_set_filler(png_ptr, 0xff, before
+ ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
+ }
+ }
+
+ rows = (png_bytep *)malloc(sizeof(png_bytep) * *height);
+ assert(rows);
+ imgdata = (unsigned char *)malloc(4 * *height * *width);
+ assert(imgdata);
+ for (uint32_t y = 0; y < *height; y++)
+ rows[y] = imgdata + 4 * *width * y;
+ png_read_image(png_ptr, rows);
+ png_read_end(png_ptr, NULL);
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ free(rows);
+
+ frame->planes[0] = imgdata;
+ frame->strides[0] = *width * 4;
+ printf("\033[32;1mloaded %ux%u\033[m\n", *width, *height);
+ return frame;
+}
+
+void png_store(struct csri_frame *frame, const char *filename,
+ uint32_t width, uint32_t height)
+{
+ enum csri_pixfmt fmt = frame->pixfmt;
+ int xforms = 0, before = 0, after = 0;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_bytep *rows;
+ FILE *fp;
+
+ fp = fopen(filename, "wb");
+ if (!fp) {
+ fprintf(stderr, "Error opening \"%s\": %s (%d)\n",
+ filename, strerror(errno), errno);
+ return;
+ }
+
+ rows = (png_bytep *)malloc(sizeof(png_bytep) * height);
+ assert(rows);
+
+ after = fmt == CSRI_F_RGB_ || fmt == CSRI_F_BGR_;
+ before = fmt == CSRI_F__RGB || fmt == CSRI_F__BGR;
+ for (uint32_t y = 0; y < height; y++) {
+ rows[y] = frame->planes[0] + frame->strides[0] * y;
+ if (before || after) {
+ unsigned char *d = rows[y], *s = rows[y],
+ *e = d + frame->strides[0];
+ if (before)
+ s++;
+ while (d < e) {
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ s++;
+ }
+ }
+ }
+
+ assert(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ NULL, NULL, NULL));
+ assert(info_ptr = png_create_info_struct(png_ptr));
+ png_init_io(png_ptr, fp);
+ if (csri_has_alpha(fmt)
+ && (fmt == CSRI_F_ARGB || fmt == CSRI_F_ABGR))
+ xforms |= PNG_TRANSFORM_SWAP_ALPHA;
+ if ((fmt < 0x200 && (fmt & 2)) || fmt == CSRI_F_BGR)
+ xforms |= PNG_TRANSFORM_BGR;
+ png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
+ png_set_IHDR(png_ptr, info_ptr, width, height, 8, csri_has_alpha(fmt)
+ ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+ png_set_rows(png_ptr, info_ptr, rows);
+ png_write_png(png_ptr, info_ptr, xforms, NULL);
+ fflush(fp);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+}
+
+#else
+struct csri_frame *png_load(const char *filename,
+ uint32_t *width, uint32_t *height, enum csri_pixfmt fmt)
+{
+ fprintf(stderr, "PNG support not compiled in.\n");
+ return NULL;
+}
+
+void png_store(struct csri_frame *frame, const char *filename,
+ uint32_t width, uint32_t height)
+{
+ fprintf(stderr, "PNG support not compiled in.\n");
+ return;
+}
+#endif
+
+struct csri_frame *frame_alloc(uint32_t width, uint32_t height,
+ enum csri_pixfmt fmt)
+{
+ int bpp;
+ unsigned char *d;
+ struct csri_frame *frame;
+
+ if (!csri_is_rgb(fmt))
+ return NULL;
+
+ bpp = fmt < CSRI_F_RGB ? 4 : 3;
+ d = (unsigned char *)malloc(width * height * bpp);
+ frame = (struct csri_frame *)malloc(sizeof(struct csri_frame));
+ if (!frame || !d)
+ return NULL;
+ memset(frame, 0, sizeof(*frame));
+ frame->pixfmt = fmt;
+ frame->strides[0] = width * bpp;
+ memset(d, csri_has_alpha(fmt) ? 0x00 : 0x80, width * height * bpp);
+ frame->planes[0] = d;
+ return frame;
+}
+
+void frame_free(struct csri_frame *frame)
+{
+ int c;
+ for (c = 0; c < 4; c++)
+ if (frame->planes[c])
+ free(frame->planes[c]);
+
+ free(frame);
+}
+
+void frame_copy(struct csri_frame *dst, struct csri_frame *src,
+ uint32_t width, uint32_t height)
+{
+ memcpy(dst->planes[0], src->planes[0], height * src->strides[0]);
+}
diff --git a/csri/frontends/cmdline/render.h b/csri/frontends/cmdline/render.h
new file mode 100644
index 000000000..77d91a315
--- /dev/null
+++ b/csri/frontends/cmdline/render.h
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#ifndef _RENDER_H
+#define _RENDER_H
+
+extern struct csri_frame *png_load(const char *filename,
+ uint32_t *width, uint32_t *height, enum csri_pixfmt fmt);
+extern void png_store(struct csri_frame *frame, const char *filename,
+ uint32_t width, uint32_t height);
+extern struct csri_frame *frame_alloc(uint32_t width, uint32_t height,
+ enum csri_pixfmt fmt);
+extern void frame_free(struct csri_frame *frame);
+extern void frame_copy(struct csri_frame *dst, struct csri_frame *src,
+ uint32_t width, uint32_t height);
+
+#endif
diff --git a/csri/include/Makefile.am b/csri/include/Makefile.am
new file mode 100644
index 000000000..7ed1e0f91
--- /dev/null
+++ b/csri/include/Makefile.am
@@ -0,0 +1,2 @@
+noinst_HEADERS = subhelp.h visibility.h
+pkginclude_HEADERS = csri/csri.h csri/openerr.h csri/logging.h csri/stream.h
diff --git a/csri/include/csri/csri.h b/csri/include/csri/csri.h
new file mode 100644
index 000000000..172428b1c
--- /dev/null
+++ b/csri/include/csri/csri.h
@@ -0,0 +1,348 @@
+/*****************************************************************************
+ * csri: common subtitle renderer interface
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+ ****************************************************************************/
+
+/** \file csri.h - main CSRI (common subtitle renderer interface) include.
+ * $Id: csri.h 45 2007-06-20 01:00:40Z equinox $ */
+
+#ifndef _CSRI_H
+/** \cond */
+#define _CSRI_H 20070119
+/** \endcond */
+
+#include /* ptrdiff_t */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSRIAPI
+/** CSRI API attributes.
+ * defaults to \c extern.
+ */
+#define CSRIAPI extern
+#endif
+
+/** \defgroup base CSRI base API. */
+/*@{*/
+
+/** pixel format specification for frames */
+enum csri_pixfmt {
+ CSRI_F_RGBA = 0,
+ CSRI_F_ARGB,
+ CSRI_F_BGRA,
+ CSRI_F_ABGR,
+
+ CSRI_F_RGB_ = 0x100,
+ CSRI_F__RGB,
+ CSRI_F_BGR_, /**< Windows "RGB32" */
+ CSRI_F__BGR,
+
+ CSRI_F_RGB = 0x200,
+ CSRI_F_BGR, /**< Windows "RGB24" */
+
+ CSRI_F_AYUV = 0x1000,
+ CSRI_F_YUVA,
+ CSRI_F_YVUA,
+
+ CSRI_F_YUY2 = 0x1100,
+
+ CSRI_F_YV12A = 0x2011, /**< planar YUV 2x2 + alpha plane */
+ CSRI_F_YV12 = 0x2111 /**< planar YUV 2x2 */
+};
+
+#define csri_is_rgb(x) ((x) < 0x1000)
+#define csri_is_yuv(x) ((x) >= 0x1000)
+#define csri_is_yuv_planar(x) ((x) >= 0x2000)
+#define csri_get_yuv_planar_xred(x) (0xf & (x))
+#define csri_get_yuv_planar_yred(x) (0xf & ((x) >> 4))
+#define csri_is_yuv_packed(x) ((x) >= 0x1000 && (x) < 0x2000)
+#define csri_has_alpha(x) (((x) & 0xfff) < 0x100)
+
+/** frame/image format specification pre-fed to the renderer */
+struct csri_fmt {
+ /** format to be used */
+ enum csri_pixfmt pixfmt;
+ /** image width, full frame.
+ *
+ * This should specify the full size of the frame.
+ * Specifying the video sub-size (in case of added black
+ * borders) is left to an extension.
+ */
+ unsigned width;
+ /** image height */
+ unsigned height;
+};
+
+/** single frame to be fed to the renderer. */
+struct csri_frame {
+ /** frame format.
+ * It is an application bug if this differs from the one
+ * passed in struct #csri_fmt to csri_query_fmt()
+ */
+ enum csri_pixfmt pixfmt;
+ /** the frame's data.
+ * Packed formats only use planes[0]; planar formats
+ * have the data ordered as Y, U, V[, A].
+ *
+ * Also note that the topmost line always comes first.
+ * The Windows biHeight strange-ity is \a NOT duplicated.
+ */
+ unsigned char *planes[4];
+ /** strides for the individual planes.
+ * Stride means full byte offset, i.e. do \a not add
+ * frame width
+ */
+ ptrdiff_t strides[4];
+};
+
+#ifndef CSRI_OWN_HANDLES
+/** opaque renderer data */
+typedef void csri_rend;
+/** opaque instance data */
+typedef void csri_inst;
+#endif
+
+#ifdef DOXYGEN
+/** disable the emission of the csri_rend and csri_inst typedefs.
+ * define this if you are in a renderer and are typedef'ing
+ * csri_rend and csri_inst to your own structs.
+ */
+#define CSRI_OWN_HANDLES
+#endif
+
+/** renderer description.
+ * \ingroup loader
+ */
+struct csri_info {
+ /** an identifier for the renderer.
+ * - MUST match the regular expression
+ * \code ^[a-zA-Z]([a-zA-Z0-9_]*[a-zA-Z0-9])? \endcode
+ * i.e. consists only of letters, numbers and underscores;
+ * must start with a letter and doesnt have an underscore
+ * as the last character.
+ */
+ const char *name;
+ /** an identifier to the exact version of the renderer.
+ * most likely a version number or revision identifier.
+ *
+ * The helper library does a strcmp over this field in order
+ * to order multiple instances of the same renderer. Use
+ * higher-byte-value strings for newer renderers.
+ */
+ const char *specific;
+
+ /** a nice name to be presented to the user */
+ const char *longname;
+ /** the renderer's author */
+ const char *author;
+ /** a copyright string. Copyright (c) 2042 by Mr. Nice Guy */
+ const char *copyright;
+};
+
+/** data of extension-dependent type.
+ * The field to be used MUST be specified in the extension where it is used.
+ */
+union csri_vardata {
+ long lval;
+ double dval;
+ const char *utf8val;
+ void *otherval;
+};
+
+/** extension identifier.
+ * This follows reverse DNS syntax, i.e.:
+ * \code root.branch.leaf \endcode
+ * you can either reverse a registered domain name, e.g.
+ * \code com.microsoft.csri.usegdiplus \endcode
+ * or ask the CSRI maintainers to assign a namespace to you.
+ *
+ * currently registered namespaces are:
+ *
+ * \code
+ * csri.* - official extensions
+ * asa.* - custom extensions of the asa renderer
+ * \endcode
+ */
+typedef const char *csri_ext_id;
+
+/** script loading parameters.
+ * each flag MUST have an associated extension, which can be queried
+ * with csri_query_ext(). If the open flag constitutes an extension on its
+ * sole own, csri_query_ext() can return a meaningless non-NULL value for
+ * it.
+ *
+ * The data field used must be specified.
+ *
+ * An extension can have multiple flags. In that case, the flags should have
+ * the extension name as common prefix, separated with a dot.
+ *
+ * A renderer MUST ignore unknown open flags. It MUST NOT return an error
+ * just because it does not support a particular flag.
+ */
+struct csri_openflag {
+ /** flag name */
+ csri_ext_id name;
+ /** flag data argument */
+ union csri_vardata data;
+ /** link to next flag */
+ struct csri_openflag *next;
+};
+
+/** load a script from a file.
+ * \param renderer the handle to the renderer
+ * \param filename the path to the file to be loaded. \n
+ * The filename should be encoded as UTF-8. Windows renderers are
+ * expected to convert it to UTF-16 and use the Unicode Windows API
+ * functions.
+ * \param flags a linked list of open flags. \n
+ * The caller manages memory allocation, i.e. static allocation is OK.
+ * \return the renderer instance handle, or NULL on error.
+ */
+CSRIAPI csri_inst *csri_open_file(csri_rend *renderer,
+ const char *filename, struct csri_openflag *flags);
+
+/** load a script from memory.
+ * \param renderer the handle to the renderer
+ * \param data pointer to the first data byte. \n
+ * The caller manages memory allocation and should free the data after
+ * calling csri_open_mem(). If the renderer needs to keep the data, it
+ * must copy it. \n
+ * The renderer is not allowed to write to the data.
+ * \param length length, in bytes, of the data
+ * \param flags see csri_open_file()
+ * \return the render instance handle, or NULL on error.
+ */
+
+CSRIAPI csri_inst *csri_open_mem(csri_rend *renderer,
+ const void *data, size_t length, struct csri_openflag *flags);
+
+/** close a renderer instance.
+ * \param inst the instance handle.
+ */
+CSRIAPI void csri_close(csri_inst *inst);
+
+
+/** query / set the image format and size.
+ * \param inst the renderer instance handle
+ * \param fmt the format and image size to be used
+ * \return 0 if the format was successfully set,
+ * any other value in case of error.
+ */
+CSRIAPI int csri_request_fmt(csri_inst *inst, const struct csri_fmt *fmt);
+
+/** render a single frame
+ * \param inst the renderer instance handle
+ * \param frame frame data to render to
+ * \param time associated timestamp of the frame
+ */
+CSRIAPI void csri_render(csri_inst *inst, struct csri_frame *frame,
+ double time);
+
+
+/** query for an extension.
+ * \param rend the renderer handle
+ * \param extname the extension's identifier
+ * \return NULL if the extension is not supported,
+ * a pointer to extension-specific data otherwise
+ *
+ * The data pointed to by the return value does not neccessarily need to
+ * have any meaning; An extension that does not need to return data
+ * can return a pointer to whatever it wants, as long as that pointer is
+ * not NULL.
+ *
+ * In the usual case, the pointer is supposed to point to a struct with
+ * function pointers and other information as needed.
+ */
+CSRIAPI void *csri_query_ext(csri_rend *rend, csri_ext_id extname);
+
+/*@}*/
+
+/** \defgroup loader CSRI loader API.
+ *
+ * These functions locate renderers based on given parameters.
+ *
+ * Renderers must implement these functions as well.
+ *
+ * They are used by the library to grab renderer information
+ * from a shared object; and also this way a single renderer
+ * can be linked directly into an appliaction.
+ */
+/*@{*/
+
+/** get renderer information
+ * \param rend the renderer handle
+ * \return information about the renderer, or NULL in case the renderer
+ * encountered an internal error.
+ */
+CSRIAPI struct csri_info *csri_renderer_info(csri_rend *rend);
+
+/** try to load a given renderer
+ * \param name the name of the renderer, as in csri_info.name
+ * \param specific the specific version of the renderer,
+ * as in csri_info.specific;\n
+ * alternatively NULL if any version of the renderer is ok.
+ * \return a handle to the renderer if it was successfully loaded,
+ * NULL otherwise.
+ */
+CSRIAPI csri_rend *csri_renderer_byname(const char *name,
+ const char *specific);
+
+/** try to find an implementation of the given extensions.
+ * \param next number of extensions pointed to by ext
+ * \param ext array of extensions to search for
+ * \return a handle to a renderer supporting ALL of the
+ * extensions, NULL if none was found.
+ */
+CSRIAPI csri_rend *csri_renderer_byext(unsigned n_ext, csri_ext_id *ext);
+
+/** get the default (highest priority) renderer
+ * \return a handle to the default renderer, or NULL if
+ * no renderer is installed.
+ *
+ * Together with csri_renderer_next(), this can be used
+ * to enumerate all installed renderers.
+ */
+CSRIAPI csri_rend *csri_renderer_default();
+
+/** get the next lower priority renderer
+ * \param prev the current renderer
+ * \return the renderer with the next lower priority than
+ * the one named in prev, or NULL if prev is the last
+ * renderer installed.
+ */
+CSRIAPI csri_rend *csri_renderer_next(csri_rend *prev);
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CSRI_H */
diff --git a/csri/include/csri/fmtids.h b/csri/include/csri/fmtids.h
new file mode 100644
index 000000000..620d818d7
--- /dev/null
+++ b/csri/include/csri/fmtids.h
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ * csri: common subtitle renderer interface
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+ ****************************************************************************/
+
+/** \file fmtids.h - csri.format - extension identifiers for subtitle formats.
+ * $Id$ */
+
+#ifndef _CSRI_FMTIDS_H
+/** \cond */
+#define _CSRI_FMTIDS_H 20070119
+/** \endcond */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup fmtids csri.format identifiers.
+ * only includes the most important ones for now, more to be added. */
+/*@{*/
+
+/** SSA / ASS. Sub Station Alpha - versions 2, 3, 4, 4+ and 4++ */
+#define CSRI_EXT_FMT_SSA (csri_ext_id)"csri.format.ssa"
+/** SRT. SubRip Text, SubRip Titles or something similar. */
+#define CSRI_EXT_FMT_SRT (csri_ext_id)"csri.format.srt"
+/** MicroDVD */
+#define CSRI_EXT_FMT_MICRODVD (csri_ext_id)"csri.format.microdvd"
+/** SAMI. Microsoft Synchronized Accessible Media Interchange */
+#define CSRI_EXT_FMT_SAMI (csri_ext_id)"csri.format.sami"
+/** SMIL. W3C Synchronized Multimedia Integration Language.
+ * NB: this format uses separate files for text streams */
+#define CSRI_EXT_FMT_SMIL (csri_ext_id)"csri.format.smil"
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CSRI_OPENERR_H */
diff --git a/csri/include/csri/logging.h b/csri/include/csri/logging.h
new file mode 100644
index 000000000..b530f4d16
--- /dev/null
+++ b/csri/include/csri/logging.h
@@ -0,0 +1,79 @@
+/*****************************************************************************
+ * csri: common subtitle renderer interface
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+ ****************************************************************************/
+
+/** \file logging.h - csri.logging - logging for renderers via callback.
+ * $Id$
+ *
+ * THE SPECIFICATION OF THIS EXTENSION IS TENTATIVE
+ * AND NOT FINALIZED YET
+ */
+
+#ifndef _CSRI_LOGGING_H
+/** \cond */
+#define _CSRI_LOGGING_H 20070119
+/** \endcond */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup logging csri.logging extension.
+ * THE SPECIFICATION OF THIS EXTENSION IS TENTATIVE
+ * AND NOT FINALIZED YET
+ */
+/*@{*/
+
+/** extension identifier */
+#define CSRI_EXT_LOGGING (csri_ext_id)"csri.logging"
+
+/** -. TODO: add scope? */
+enum csri_logging_severity {
+ CSRI_LOG_DEBUG = 0,
+ CSRI_LOG_INFO,
+ CSRI_LOG_NOTICE,
+ CSRI_LOG_WARNING,
+ CSRI_LOG_ERROR
+};
+
+typedef void csri_logging_func(void *appdata,
+ enum csri_logging_severity sev,
+ const char *message);
+
+struct csri_logging_ext {
+ void (*set_logcallback)(csri_logging_func *func, void *appdata);
+};
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CSRI_LOGGING_H */
diff --git a/csri/include/csri/openerr.h b/csri/include/csri/openerr.h
new file mode 100644
index 000000000..a5b1fd7ff
--- /dev/null
+++ b/csri/include/csri/openerr.h
@@ -0,0 +1,124 @@
+/*****************************************************************************
+ * csri: common subtitle renderer interface
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+ ****************************************************************************/
+
+/** \file openerr.h - csri.openerr - error return extension.
+ * $Id$ */
+
+#ifndef _CSRI_OPENERR_H
+/** \cond */
+#define _CSRI_OPENERR_H 20070119
+/** \endcond */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup openerr csri.openerr extension. */
+/*@{*/
+
+/** extension identifier */
+#define CSRI_EXT_OPENERR (csri_ext_id)"csri.openerr"
+
+/** flag field describing which fields of #csri_openerr_flag are valid */
+enum csri_openerr_flags {
+ /** support indicator.
+ * set if the structure was filled with any meaningful data
+ */
+ CSRI_OPENERR_FILLED = (1 << 0),
+ /** csri_openerr_flag.posixerrno valid */
+ CSRI_OPENERR_ERRNO = (1 << 1),
+ /** csri_openerr_flag.winerr valid */
+ CSRI_OPENERR_WINERR = (1 << 2),
+ /** csri_openerr_flag.custerr valid */
+ CSRI_OPENERR_CUSTERR = (1 << 3),
+ /** csri_openerr_flag.warncount valid */
+ CSRI_OPENERR_WARNCOUNT = (1 << 4)
+};
+
+/** returned error information.
+ * to be passed via csri_vardata.otherval as an openflag with
+ * extension ID #CSRI_EXT_OPENERR.
+ *
+ * Memory management by caller.
+ *
+ * The three error fields should only be filled when csri_open_file()
+ * / csri_open_mem() returned NULL. The warning counter can indicate
+ * information on successfully loaded scripts.
+ */
+struct csri_openerr_flag {
+ /** bitfield of valid information */
+ enum csri_openerr_flags flags;
+ /** posix errno value indicating the error occured */
+ int posixerrno;
+ /** Windows GetLastError value */
+ unsigned winerr;
+ /** renderer-specific custom error value.
+ * should be string-lookupable via csri_openerr_ext.strerror
+ * (csri_query_ext())
+ */
+ union csri_vardata custerr;
+ /** warning count.
+ * The number of (renderer-specific) warnings that occured
+ * during loading the script. The content of these warnings
+ * should be retrievable via a renderer-specific extension.
+ */
+ unsigned warncount;
+};
+
+/** openerr extension information structure */
+struct csri_openerr_ext {
+ /** csri_openerr_flag.custerr to string lookup.
+ * \param renderer the renderer handle.
+ * \param custerr renderer-specific error
+ * \param buffer buffer to fill with an UTF-8 error message.
+ * may be NULL; in that case only size is filled in
+ * \param size buffer size.\n
+ * in: maximum bytes to write to buffer, in bytes,
+ * including terminating \\0.\nthe renderer MUST always
+ * zero-terminate this, even when the space is not sufficient
+ * \n\n
+ * out: number of bytes (including terminating \\0) needed
+ * to return the full error message
+ *
+ * This function pointer may be NULL if the renderer does not
+ * return custom error codes. #CSRI_OPENERR_CUSTERR must not be
+ * used in that case.
+ */
+ void (*strerror)(csri_rend *renderer, union csri_vardata custerr,
+ char *buffer, size_t *size);
+};
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CSRI_OPENERR_H */
diff --git a/csri/include/csri/stream.h b/csri/include/csri/stream.h
new file mode 100644
index 000000000..cc24d97d6
--- /dev/null
+++ b/csri/include/csri/stream.h
@@ -0,0 +1,143 @@
+/*****************************************************************************
+ * csri: common subtitle renderer interface
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+ ****************************************************************************/
+
+/** \file stream.h - subtitle streaming (MKV & co).
+ * $Id$
+ *
+ * THE SPECIFICATION OF THIS EXTENSION IS TENTATIVE
+ * AND NOT FINALIZED YET
+ */
+
+#ifndef _CSRI_STREAM_H
+/** \cond */
+#define _CSRI_STREAM_H 20070119
+/** \endcond */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup stream csri.stream.* extensions. */
+/*@{*/
+
+/** stream extension group.
+ * note: you cannot query for csri.stream, you need
+ * to query for one of the streaming formats instead,
+ * which will return a csri_stream_ext pointer.
+ */
+#define CSRI_EXT_STREAM (csri_ext_id)"csri.stream"
+
+/** Matroska-style ASS streaming.
+ * header contains standard SSA stuff, packet contains
+ * ReadOrder,Layer,Style,Speaker,MarginL,R,V,Effect,Text
+ */
+#define CSRI_EXT_STREAM_ASS CSRI_EXT_STREAM ".ass"
+/** Simple text + timestamp streams */
+#define CSRI_EXT_STREAM_TEXT CSRI_EXT_STREAM ".text"
+/* missing: USF, MPEG-4 TT */
+
+/** stream extension information structure */
+struct csri_stream_ext {
+ /** create streaming renderer instance.
+ * \param renderer the renderer handle.
+ * \param header codec-private stream header.
+ * \param headerlen byte length of header data.
+ * \param flags openflags.
+ *
+ * not NULL if this extension is supported.
+ * may take various flags like csri_openerr_flag.
+ *
+ * the returned instance can be used with
+ * csri_request_fmt, csri_render and csri_close.
+ */
+ csri_inst *(*init_stream)(csri_rend *renderer,
+ const void *header, size_t headerlen,
+ struct csri_openflag *flags);
+
+ /** process a streamed packet.
+ * \param inst instance created with init_stream.
+ * \param packet stream packet data.
+ * \param packetlen byte length of packet.
+ * \param pts_start start timestamp from container.
+ * \param pts_end end timestamp from container.
+ *
+ * add a single packet to the renderer instance.
+ */
+ void (*push_packet)(csri_inst *inst,
+ const void *packet, size_t packetlen,
+ double pts_start, double pts_end);
+
+ /** discard processed packets.
+ * \param inst instance created with init_stream.
+ * \param all discard possibly-active packets too.\n
+ * a possibly-active packet is a packet which
+ * has not seen a csri_render call with a pts
+ * beyond its end timestamp yet.
+ *
+ * frees up memory, or can force a clean renderer.
+ * may be NULL if unsupported, check before calling!
+ */
+ void (*discard)(csri_inst *inst, int all);
+};
+
+/** streaming openflag ext for controlling subtitle lifetime */
+#define CSRI_EXT_STREAM_DISCARD CSRI_EXT_STREAM ".discard"
+
+/** subtitle packet lifetime */
+enum csri_stream_discard {
+ /** lifetime: timestamp expiry.
+ * delete packets from csri_render if the current
+ * timestamp is beyond the packet's end timestamp.
+ * this should be the default
+ */
+ CSRI_STREAM_DISCARD_TSEXPIRE = 0,
+ /** lifetime: discard immediately.
+ * discard all packets on returning from csri_render.
+ */
+ CSRI_STREAM_DISCARD_IMMEDIATELY,
+ /** lifetime: discard explicitly.
+ * never discard packets, use csri_stream_ext.discard
+ */
+ CSRI_STREAM_DISCARD_EXPLICIT
+};
+
+/** openflag for csri_stream_ext.init_stream */
+struct csri_stream_discard_flag {
+ /** the lifetime to be used for subtitle packets */
+ enum csri_stream_discard lifetime;
+};
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CSRI_STREAM_H */
diff --git a/csri/include/subhelp.h b/csri/include/subhelp.h
new file mode 100644
index 000000000..ffde5d992
--- /dev/null
+++ b/csri/include/subhelp.h
@@ -0,0 +1,114 @@
+/*****************************************************************************
+ * csri: common subtitle renderer interface
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+ ****************************************************************************/
+
+/** \file subhelp.h - subtitle helper API.
+ * $Id$ */
+
+#ifndef _SUBHELP_H
+#define _SUBHELP_H
+
+#include
+#include
+#include
+
+/** \defgroup subhelp subtitle filter helper API. */
+/*@{*/
+
+/** file opening wrapper.
+ * can be used to implement csri_open_file() by using csri_open_mem().
+ * \param renderer the renderer handle
+ * \param memopenfunc function pointer to a csri_open_mem() implementation
+ * \param filename name of file to open
+ * \param flags pointer #csri_openflag.\n
+ * subhelp_open_file will fill in csri.openerr if present
+ * \return return value from memopenfunc or NULL on fs error
+ */
+extern csri_inst *subhelp_open_file(csri_rend *renderer,
+ csri_inst *(*memopenfunc)(csri_rend *renderer, const void *data,
+ size_t length, struct csri_openflag *flags),
+ const char *filename, struct csri_openflag *flags);
+
+
+/** logging extension query function.
+ * call from csri_query_ext BEFORE checking whether the renderer.
+ * \code
+ * void *csri_query_ext(csri_rend *rend, csri_ext_id extname) {
+ * void *rv;
+ * if ((rv = subhelp_query_ext_logging(extname)))
+ * return rv;
+ * if (!rend)
+ * return NULL;
+ * ...
+ * \endcode
+ * \param extname the extension name. compared to "csri.logging" by
+ * this function.
+ * \return logging extension pointer, if the extension name matched.
+ * NULL otherwise.
+ */
+extern void *subhelp_query_ext_logging(csri_ext_id extname);
+
+/** configure other renderer with our settings.
+ * \param logext csri.logging from configuree.
+ */
+extern void subhelp_logging_pass(struct csri_logging_ext *logext);
+
+/** logging function.
+ * \param severity severity of this message, as defined by csri.logging
+ * \param msg log message, one line, without \\n at the end.
+ */
+extern void subhelp_log(enum csri_logging_severity severity,
+ const char *msg, ...)
+#ifdef __GNUC__
+ __attribute__((format(printf, 2, 3)))
+#endif
+ ;
+
+/** logging function, varargs version.
+ * \param severity severity of this message, as defined by csri.logging
+ * \param msg log message, one line, without \\n at the end.
+ * \param args argument list
+ */
+extern void subhelp_vlog(enum csri_logging_severity severity,
+ const char *msg, va_list args)
+#ifdef __GNUC__
+ __attribute__((format(printf, 2, 0)))
+#endif
+ ;
+
+/** logging function, fixed string version.
+ * \param severity severity of this message, as defined by csri.logging
+ * \param msg log message, one line, without \\n at the end.
+ */
+extern void subhelp_slog(enum csri_logging_severity severity, const char *msg);
+
+/*@}*/
+
+#endif /* _SUBHELP_H */
+
diff --git a/csri/include/visibility.h b/csri/include/visibility.h
new file mode 100644
index 000000000..632f07ef2
--- /dev/null
+++ b/csri/include/visibility.h
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+
+#ifndef _VISIBILITY_H
+#define _VISIBILITY_H
+
+#ifdef HAVE_CONFIG_H
+#include "acconf.h"
+#endif
+
+#ifdef _WIN32
+#define export __declspec(dllexport)
+#define internal
+#define hidden
+#elif HAVE_GCC_VISIBILITY
+#define export __attribute__((visibility ("default")))
+#define internal __attribute__((visibility ("internal")))
+#define hidden __attribute__((visibility ("hidden")))
+#else
+#define export
+#define internal
+#define hidden
+#endif
+
+#endif /* _VISIBILITY_H */
diff --git a/csri/lib/Makefile.am b/csri/lib/Makefile.am
new file mode 100644
index 000000000..7bea258d3
--- /dev/null
+++ b/csri/lib/Makefile.am
@@ -0,0 +1,14 @@
+if BUILD_MINGW
+PLATF = win32
+else
+PLATF = posix
+AM_CPPFLAGS = -DCSRI_PATH="\"$(csri_path)\""
+endif
+lib_LTLIBRARIES = libcsri.la
+noinst_HEADERS = csrilib.h posix/csrilib_os.h win32/csrilib_os.h
+libcsri_la_SOURCES = list.c wrap.c $(PLATF)/enumerate.c
+libcsri_la_CFLAGS = -I$(top_srcdir)/lib/posix -I$(top_srcdir)/include
+libcsri_la_LIBADD = ../subhelp/libsubhelp_la-logging.lo
+libcsri_la_LDFLAGS = -static
+
+EXTRA_DIST = posix/enumerate.c win32/enumerate.c
diff --git a/csri/lib/csrilib.h b/csri/lib/csrilib.h
new file mode 100644
index 000000000..66a6a27e8
--- /dev/null
+++ b/csri/lib/csrilib.h
@@ -0,0 +1,85 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#ifndef _CSRILIB_H
+#define _CSRILIB_H
+
+#ifdef HAVE_CONFIG_H
+#include "acconf.h"
+#endif
+
+#include "visibility.h"
+
+#define CSRIAPI export
+
+#include
+#include
+#include "csrilib_os.h"
+
+struct csri_wrap_rend {
+ struct csri_wrap_rend *next;
+
+ csri_rend *rend;
+ csri_inst *(*open_file)(csri_rend *renderer,
+ const char *filename, struct csri_openflag *flags);
+ csri_inst *(*open_mem)(csri_rend *renderer,
+ const void *data, size_t length,
+ struct csri_openflag *flags);
+ void (*close)(csri_inst *inst);
+ int (*request_fmt)(csri_inst *inst, const struct csri_fmt *fmt);
+ void (*render)(csri_inst *inst, struct csri_frame *frame,
+ double time);
+ void *(*query_ext)(csri_rend *rend, csri_ext_id extname);
+ struct csri_stream_ext stream_ass, stream_text;
+ csri_inst *(*init_stream_ass)(csri_rend *renderer,
+ const void *header, size_t headerlen,
+ struct csri_openflag *flags);
+ csri_inst *(*init_stream_text)(csri_rend *renderer,
+ const void *header, size_t headerlen,
+ struct csri_openflag *flags);
+
+ struct csri_info *info;
+ struct csrilib_os os;
+};
+
+struct csri_wrap_inst {
+ struct csri_wrap_inst *next;
+
+ csri_inst *inst;
+ struct csri_wrap_rend *wrend;
+ void (*close)(csri_inst *inst);
+ int (*request_fmt)(csri_inst *inst, const struct csri_fmt *fmt);
+ void (*render)(csri_inst *inst, struct csri_frame *frame,
+ double time);
+};
+
+extern struct csri_wrap_rend *wraprends;
+
+extern struct csri_wrap_rend *csrilib_rend_lookup(csri_rend *rend);
+extern void csrilib_rend_initadd(struct csri_wrap_rend *wrend);
+
+extern struct csri_wrap_inst *csrilib_inst_lookup(csri_inst *inst);
+extern csri_inst *csrilib_inst_initadd(struct csri_wrap_rend *wrend,
+ csri_inst *inst);
+extern void csrilib_inst_remove(struct csri_wrap_inst *winst);
+
+extern void csrilib_os_init();
+
+#endif /*_CSRILIB_H */
diff --git a/csri/lib/list.c b/csri/lib/list.c
new file mode 100644
index 000000000..3c5826698
--- /dev/null
+++ b/csri/lib/list.c
@@ -0,0 +1,148 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#include
+#include
+#include
+#include
+
+#include "csrilib.h"
+
+struct csri_wrap_rend *wraprends = NULL;
+
+struct csri_wrap_rend *csrilib_rend_lookup(csri_rend *rend)
+{
+ struct csri_wrap_rend *wrap = wraprends;
+ for (; wrap; wrap = wrap->next)
+ if (wrap->rend == rend)
+ return wrap;
+ return NULL;
+}
+
+#define INSTHASHSZ 256
+#define HASH(x) (((intptr_t)(x) & 0xff00) >> 8)
+static struct csri_wrap_inst *wrapinsts[INSTHASHSZ];
+
+struct csri_wrap_inst *csrilib_inst_lookup(csri_inst *inst)
+{
+ struct csri_wrap_inst *ent = wrapinsts[HASH(inst)];
+ while (ent && ent->inst != inst)
+ ent = ent->next;
+ return ent;
+}
+
+csri_inst *csrilib_inst_initadd(struct csri_wrap_rend *wrend,
+ csri_inst *inst)
+{
+ struct csri_wrap_inst *winst = (struct csri_wrap_inst *)
+ malloc(sizeof(struct csri_wrap_inst)),
+ **pnext;
+ if (!winst) {
+ wrend->close(inst);
+ return NULL;
+ }
+ winst->wrend = wrend;
+ winst->inst = inst;
+ winst->close = wrend->close;
+ winst->request_fmt = wrend->request_fmt;
+ winst->render = wrend->render;
+ winst->next = NULL;
+ pnext = &wrapinsts[HASH(inst)];
+ while (*pnext)
+ pnext = &(*pnext)->next;
+ *pnext = winst;
+ return inst;
+}
+
+void csrilib_inst_remove(struct csri_wrap_inst *winst)
+{
+ struct csri_wrap_inst **pnext = &wrapinsts[HASH(winst->inst)];
+ while (*pnext && *pnext != winst)
+ pnext = &(*pnext)->next;
+ if (!*pnext)
+ return;
+ *pnext = (*pnext)->next;
+}
+
+void csrilib_rend_initadd(struct csri_wrap_rend *wrend)
+{
+ wrend->next = wraprends;
+ wraprends = wrend;
+}
+
+static int initialized = 0;
+
+csri_rend *csri_renderer_default()
+{
+ if (!initialized) {
+ csrilib_os_init();
+ initialized = 1;
+ }
+ if (!wraprends)
+ return NULL;
+ return wraprends->rend;
+}
+
+csri_rend *csri_renderer_next(csri_rend *prev)
+{
+ struct csri_wrap_rend *wrend = csrilib_rend_lookup(prev);
+ if (!wrend || !wrend->next)
+ return NULL;
+ return wrend->next->rend;
+}
+
+csri_rend *csri_renderer_byname(const char *name, const char *specific)
+{
+ struct csri_wrap_rend *wrend;
+ if (!initialized) {
+ csrilib_os_init();
+ initialized = 1;
+ }
+ if (!name)
+ return NULL;
+ for (wrend = wraprends; wrend; wrend = wrend->next) {
+ if (strcmp(wrend->info->name, name))
+ continue;
+ if (specific && strcmp(wrend->info->specific, specific))
+ continue;
+ return wrend->rend;
+ }
+ return NULL;
+}
+
+csri_rend *csri_renderer_byext(unsigned n_ext, csri_ext_id *ext)
+{
+ struct csri_wrap_rend *wrend;
+ unsigned i;
+ if (!initialized) {
+ csrilib_os_init();
+ initialized = 1;
+ }
+ for (wrend = wraprends; wrend; wrend = wrend->next) {
+ for (i = 0; i < n_ext; i++) {
+ if (!wrend->query_ext(wrend->rend, ext[i]))
+ break;
+ }
+ if (i == n_ext)
+ return wrend->rend;
+ }
+ return NULL;
+}
+
diff --git a/csri/lib/posix/csrilib_os.h b/csri/lib/posix/csrilib_os.h
new file mode 100644
index 000000000..d8b780233
--- /dev/null
+++ b/csri/lib/posix/csrilib_os.h
@@ -0,0 +1,27 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#include
+
+struct csrilib_os {
+ void *dlhandle;
+ dev_t device;
+ ino_t inode;
+};
diff --git a/csri/lib/posix/enumerate.c b/csri/lib/posix/enumerate.c
new file mode 100644
index 000000000..ab4eb06bc
--- /dev/null
+++ b/csri/lib/posix/enumerate.c
@@ -0,0 +1,199 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#define _POSIX_C_SOURCE 200112L /* for PATH_MAX */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../csrilib.h"
+#include "subhelp.h"
+
+static const char csri_path[] = CSRI_PATH;
+
+static void csrilib_enum_dir(const char *dir);
+
+static void csrilib_add(csri_rend *rend,
+ const struct csri_wrap_rend *tmp, struct csri_info *info)
+{
+ struct csri_wrap_rend *wrend = (struct csri_wrap_rend *)
+ malloc(sizeof(struct csri_wrap_rend));
+ if (!wrend)
+ return;
+ memcpy(wrend, tmp, sizeof(struct csri_wrap_rend));
+ wrend->rend = rend;
+ wrend->info = info;
+ csrilib_rend_initadd(wrend);
+}
+
+static void csrilib_do_load(const char *filename, dev_t device, ino_t inode)
+{
+ void *dlhandle = dlopen(filename, RTLD_NOW);
+ struct csri_wrap_rend tmp;
+ csri_rend *rend;
+ struct csri_info *(*renderer_info)(csri_rend *rend);
+ csri_rend *(*renderer_default)();
+ csri_rend *(*renderer_next)(csri_rend *prev);
+ const char *sym;
+
+
+ if (!dlhandle) {
+ subhelp_log(CSRI_LOG_WARNING, "dlopen(\"%s\") says: %s",
+ filename, dlerror());
+ return;
+ }
+ if (dlsym(dlhandle, "csri_library")) {
+ subhelp_log(CSRI_LOG_WARNING, "ignoring library %s",
+ filename);
+ return;
+ }
+ subhelp_log(CSRI_LOG_INFO, "loading %s", filename);
+
+ tmp.os.dlhandle = dlhandle;
+ tmp.os.device = device;
+ tmp.os.inode = inode;
+
+/* okay, this is uber-ugly. either I end up casting from void *
+ * to a fptr (which yields a cast warning), or I do a *(void **)&tmp.x
+ * (which yields a strict-aliasing warning).
+ * casting via char* works because char* can alias anything.
+ */
+#define _dl_map_function(x, dst) do { \
+ char *t1 = (char *)&dst; \
+ union x { void *ptr; } *ptr = (union x *)t1; \
+ sym = "csri_" # x; \
+ ptr->ptr = dlsym(dlhandle, sym);\
+ if (!ptr->ptr) goto out_dlfail; } while (0)
+#define dl_map_function(x) _dl_map_function(x, tmp.x)
+ dl_map_function(query_ext);
+ subhelp_logging_pass((struct csri_logging_ext *)
+ tmp.query_ext(NULL, CSRI_EXT_LOGGING));
+ dl_map_function(open_file);
+ dl_map_function(open_mem);
+ dl_map_function(close);
+ dl_map_function(request_fmt);
+ dl_map_function(render);
+#define dl_map_local(x) _dl_map_function(x, x)
+ dl_map_local(renderer_info);
+ dl_map_local(renderer_default);
+ dl_map_local(renderer_next);
+
+ rend = renderer_default();
+ while (rend) {
+ csrilib_add(rend, &tmp, renderer_info(rend));
+ rend = renderer_next(rend);
+ }
+ return;
+
+out_dlfail:
+ subhelp_log(CSRI_LOG_WARNING, "%s: symbol %s not found (%s)",
+ filename, sym, dlerror());
+ dlclose(dlhandle);
+}
+
+static void csrilib_load(const char *filename)
+{
+ struct csri_wrap_rend *rend;
+ struct stat st;
+ if (stat(filename, &st))
+ return;
+
+ if (S_ISDIR(st.st_mode)) {
+ csrilib_enum_dir(filename);
+ return;
+ }
+ if (!S_ISREG(st.st_mode))
+ return;
+ if (access(filename, X_OK))
+ return;
+
+ for (rend = wraprends; rend; rend = rend->next)
+ if (rend->os.device == st.st_dev
+ && rend->os.inode == st.st_ino)
+ return;
+
+ csrilib_do_load(filename, st.st_dev, st.st_ino);
+}
+
+static void csrilib_enum_dir(const char *dir)
+{
+ DIR *dirh;
+ struct dirent *e;
+ char buf[PATH_MAX];
+
+ dirh = opendir(dir);
+ if (!dirh) {
+ subhelp_log(CSRI_LOG_WARNING, "ignoring directory \"%s\":"
+ " %s (%d)", dir, strerror(errno), errno);
+ return;
+ }
+
+ subhelp_log(CSRI_LOG_INFO, "scanning directory \"%s\"", dir);
+ while ((e = readdir(dirh))) {
+ if (e->d_name[0] == '.')
+ continue;
+ snprintf(buf, sizeof(buf), "%s/%s", dir, e->d_name);
+ csrilib_load(buf);
+ }
+
+ closedir(dirh);
+}
+
+static void csrilib_expand_enum_dir(const char *dir)
+{
+ if (dir[0] == '~' && (dir[1] == '\0' || dir[1] == '/')) {
+ char buf[PATH_MAX], *home = getenv("HOME");
+ if (!home)
+ home = "";
+ snprintf(buf, sizeof(buf), "%s%s", home, dir + 1);
+ csrilib_enum_dir(buf);
+ } else
+ csrilib_enum_dir(dir);
+}
+
+void csrilib_os_init()
+{
+ char buf[4096];
+ char *envpath = getenv("CSRI_PATH");
+ char *pos, *next = buf;
+
+ if (envpath)
+ snprintf(buf, sizeof(buf), "%s:%s", csri_path, envpath);
+ else {
+ strncpy(buf, csri_path, sizeof(buf));
+ buf[sizeof(buf) - 1] = '\0';
+ }
+ do {
+ pos = next;
+ next = strchr(pos, ':');
+ if (next)
+ *next++ = '\0';
+ csrilib_expand_enum_dir(pos);
+ } while (next);
+}
+
diff --git a/csri/lib/win32/csrilib_os.h b/csri/lib/win32/csrilib_os.h
new file mode 100644
index 000000000..c40014d99
--- /dev/null
+++ b/csri/lib/win32/csrilib_os.h
@@ -0,0 +1,25 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#include
+
+struct csrilib_os {
+ HMODULE dlhandle;
+};
diff --git a/csri/lib/win32/enumerate.c b/csri/lib/win32/enumerate.c
new file mode 100644
index 000000000..74c5b925a
--- /dev/null
+++ b/csri/lib/win32/enumerate.c
@@ -0,0 +1,175 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#include
+#include
+#include
+#include
+
+#include "../csrilib.h"
+#include "subhelp.h"
+
+static void csrilib_enum_dir(const wchar_t *dir);
+
+static const char *get_errstr()
+{
+ static char msg[2048];
+ DWORD err = GetLastError();
+
+ if (!FormatMessageA(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, err, 0, msg, sizeof(msg), NULL))
+ strcpy(msg, "Unknown Error");
+ else {
+ int msglen = strlen(msg) - 1;
+ if (msg[msglen] == '\n')
+ msg[msglen] = '\0';
+ }
+ return msg;
+}
+
+static void csrilib_add(csri_rend *rend,
+ const struct csri_wrap_rend *tmp, struct csri_info *info)
+{
+ struct csri_wrap_rend *wrend = (struct csri_wrap_rend *)
+ malloc(sizeof(struct csri_wrap_rend));
+ if (!wrend)
+ return;
+ memcpy(wrend, tmp, sizeof(struct csri_wrap_rend));
+ wrend->rend = rend;
+ wrend->info = info;
+ csrilib_rend_initadd(wrend);
+}
+
+static void csrilib_do_load(const wchar_t *filename)
+{
+ HMODULE dlhandle = LoadLibraryExW(filename, NULL,
+ LOAD_WITH_ALTERED_SEARCH_PATH);
+ struct csri_wrap_rend tmp;
+ csri_rend *rend;
+ struct csri_info *(*renderer_info)(csri_rend *rend);
+ csri_rend *(*renderer_default)();
+ csri_rend *(*renderer_next)(csri_rend *prev);
+ const char *sym;
+
+ if (!dlhandle) {
+ subhelp_log(CSRI_LOG_WARNING, "LoadLibraryEx(\"%ls\") failed: "
+ "%s", filename, get_errstr());
+ return;
+ }
+ if (GetProcAddress(dlhandle, "csri_library")) {
+ subhelp_log(CSRI_LOG_WARNING, "ignoring library %ls",
+ filename);
+ goto out_freelib;
+ }
+ subhelp_log(CSRI_LOG_INFO, "loading %ls", filename);
+
+ tmp.os.dlhandle = dlhandle;
+
+/* okay, this is uber-ugly. either I end up casting from void *
+ * to a fptr (which yields a cast warning), or I do a *(void **)&tmp.x
+ * (which yields a strict-aliasing warning).
+ * casting via char* works because char* can alias anything.
+ */
+#define _dl_map_function(x, dst) do { \
+ char *t1 = (char *)&dst; \
+ union x { FARPROC ptr; } *ptr = (union x *)t1; \
+ sym = "csri_" # x; \
+ ptr->ptr = GetProcAddress(dlhandle, sym);\
+ if (!ptr->ptr) goto out_dlfail; } while (0)
+#define dl_map_function(x) _dl_map_function(x, tmp.x)
+ dl_map_function(query_ext);
+ subhelp_logging_pass((struct csri_logging_ext *)
+ tmp.query_ext(NULL, CSRI_EXT_LOGGING));
+ dl_map_function(open_file);
+ dl_map_function(open_mem);
+ dl_map_function(close);
+ dl_map_function(request_fmt);
+ dl_map_function(render);
+#define dl_map_local(x) _dl_map_function(x, x)
+ dl_map_local(renderer_info);
+ dl_map_local(renderer_default);
+ dl_map_local(renderer_next);
+
+ rend = renderer_default();
+ while (rend) {
+ csrilib_add(rend, &tmp, renderer_info(rend));
+ rend = renderer_next(rend);
+ }
+ return;
+
+out_dlfail:
+ subhelp_log(CSRI_LOG_WARNING, "%ls: symbol %s not found (%s)",
+ filename, sym, get_errstr());
+out_freelib:
+ FreeLibrary(dlhandle);
+}
+
+static void csrilib_load(const wchar_t *filename)
+{
+ DWORD attr = GetFileAttributesW(filename);
+ if (attr == INVALID_FILE_ATTRIBUTES)
+ return;
+
+ if (attr & FILE_ATTRIBUTE_DIRECTORY) {
+ csrilib_enum_dir(filename);
+ return;
+ }
+ csrilib_do_load(filename);
+}
+
+static void csrilib_enum_dir(const wchar_t *dir)
+{
+ WIN32_FIND_DATAW data;
+ HANDLE res;
+ wchar_t buf[MAX_PATH];
+
+ _snwprintf(buf, sizeof(buf) / sizeof(buf[0]), L"%ls\\*", dir);
+ res = FindFirstFileW(buf, &data);
+ if (res == INVALID_HANDLE_VALUE) {
+ subhelp_log(CSRI_LOG_WARNING, "ignoring directory \"%ls\": %s",
+ dir, get_errstr());
+ return;
+ }
+
+ subhelp_log(CSRI_LOG_INFO, "scanning directory \"%ls\"", dir);
+ do {
+ if (data.cFileName[0] == '.')
+ continue;
+ _snwprintf(buf, sizeof(buf) / sizeof(buf[0]),
+ L"%ls\\%ls", dir, data.cFileName);
+ csrilib_load(buf);
+ } while (FindNextFileW(res, &data));
+ FindClose(res);
+}
+
+void csrilib_os_init()
+{
+ wchar_t filename[MAX_PATH], *slash;
+ DWORD rv = GetModuleFileNameW(NULL, filename, MAX_PATH);
+ if (!rv)
+ *filename = L'\0';
+ slash = wcsrchr(filename, L'\\');
+ slash = slash ? slash + 1 : filename;
+ *slash = L'\0';
+ wcsncpy(slash, L"csri", filename + MAX_PATH - slash);
+ csrilib_enum_dir(filename);
+}
+
diff --git a/csri/lib/wrap.c b/csri/lib/wrap.c
new file mode 100644
index 000000000..51e37da33
--- /dev/null
+++ b/csri/lib/wrap.c
@@ -0,0 +1,118 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#include "csrilib.h"
+#include "subhelp.h"
+
+#include
+
+csri_inst *csri_open_file(csri_rend *rend,
+ const char *filename, struct csri_openflag *flags)
+{
+ struct csri_wrap_rend *wrend = csrilib_rend_lookup(rend);
+ if (!wrend)
+ return NULL;
+ return csrilib_inst_initadd(wrend,
+ wrend->open_file(rend, filename, flags));
+}
+
+#define instance_wrapper(wrapname, funcname) \
+csri_inst *wrapname(csri_rend *rend, \
+ const void *data, size_t length, struct csri_openflag *flags) \
+{ \
+ struct csri_wrap_rend *wrend = csrilib_rend_lookup(rend); \
+ if (!wrend) \
+ return NULL; \
+ return csrilib_inst_initadd(wrend, \
+ wrend->funcname(rend, data, length, flags)); \
+}
+
+instance_wrapper(csri_open_mem, open_mem)
+static instance_wrapper(wrap_init_stream_ass, init_stream_ass)
+static instance_wrapper(wrap_init_stream_text, init_stream_text)
+
+void *csri_query_ext(csri_rend *rend, csri_ext_id extname)
+{
+ struct csri_wrap_rend *wrend;
+ void *rv;
+
+ if (!rend && (rv = subhelp_query_ext_logging(extname)))
+ return rv;
+
+ wrend = csrilib_rend_lookup(rend);
+ if (!wrend)
+ return NULL;
+ rv = wrend->query_ext(rend, extname);
+ if (rv && !strcmp(extname, CSRI_EXT_STREAM_ASS)) {
+ struct csri_stream_ext *e = (struct csri_stream_ext *)rv;
+ memcpy(&wrend->stream_ass, e, sizeof(*e));
+ wrend->init_stream_ass = e->init_stream;
+ wrend->stream_ass.init_stream = wrap_init_stream_ass;
+ return &wrend->stream_ass;
+ }
+ if (rv && !strcmp(extname, CSRI_EXT_STREAM_TEXT)) {
+ struct csri_stream_ext *e = (struct csri_stream_ext *)rv;
+ memcpy(&wrend->stream_text, e, sizeof(*e));
+ wrend->init_stream_text = e->init_stream;
+ wrend->stream_text.init_stream = wrap_init_stream_text;
+ return &wrend->stream_text;
+ }
+ return rv;
+}
+
+struct csri_info *csri_renderer_info(csri_rend *rend)
+{
+ struct csri_wrap_rend *wrend = csrilib_rend_lookup(rend);
+ if (!wrend)
+ return NULL;
+ return wrend->info;
+}
+
+void csri_close(csri_inst *inst)
+{
+ struct csri_wrap_inst *winst = csrilib_inst_lookup(inst);
+ if (!winst)
+ return;
+ winst->close(inst);
+ csrilib_inst_remove(winst);
+}
+
+int csri_request_fmt(csri_inst *inst, const struct csri_fmt *fmt)
+{
+ struct csri_wrap_inst *winst = csrilib_inst_lookup(inst);
+ if (!winst)
+ return 0;
+ return winst->request_fmt(inst, fmt);
+}
+
+void csri_render(csri_inst *inst, struct csri_frame *frame,
+ double time)
+{
+ struct csri_wrap_inst *winst = csrilib_inst_lookup(inst);
+ if (!winst)
+ return;
+ winst->render(inst, frame, time);
+}
+
+const char *csri_library()
+{
+ return "DEV";
+}
+
diff --git a/csri/subhelp/Makefile.am b/csri/subhelp/Makefile.am
new file mode 100644
index 000000000..449853cd6
--- /dev/null
+++ b/csri/subhelp/Makefile.am
@@ -0,0 +1,10 @@
+if BUILD_MINGW
+PLATF = win32
+else
+PLATF = posix
+endif
+noinst_LTLIBRARIES = libsubhelp.la
+libsubhelp_la_SOURCES = $(PLATF)/openfile.c logging.c
+libsubhelp_la_CFLAGS = -I$(top_srcdir)/include
+
+EXTRA_DIST = win32/openfile.c posix/openfile.c
diff --git a/csri/subhelp/logging.c b/csri/subhelp/logging.c
new file mode 100644
index 000000000..e34978d05
--- /dev/null
+++ b/csri/subhelp/logging.c
@@ -0,0 +1,102 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "acconf.h"
+#endif
+
+#include
+#include
+#include
+#include
+
+#include "visibility.h"
+#include "subhelp.h"
+#include
+
+static void *appdata = NULL;
+static csri_logging_func *logfunc = NULL;
+
+void setlogcallback(csri_logging_func *_logfunc, void *_appdata) hidden;
+
+void setlogcallback(csri_logging_func *_logfunc, void *_appdata)
+{
+ logfunc = _logfunc;
+ appdata = _appdata;
+}
+
+static struct csri_logging_ext logext = {
+ setlogcallback
+};
+
+void subhelp_logging_pass(struct csri_logging_ext *nlogext)
+{
+ if (!nlogext || !nlogext->set_logcallback)
+ return;
+ nlogext->set_logcallback(logfunc, appdata);
+}
+
+void *subhelp_query_ext_logging(csri_ext_id extname)
+{
+ if (strcmp(extname, CSRI_EXT_LOGGING))
+ return NULL;
+ return &logext;
+}
+
+void subhelp_log(enum csri_logging_severity severity, const char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ subhelp_vlog(severity, msg, args);
+ va_end(args);
+}
+
+void subhelp_vlog(enum csri_logging_severity severity,
+ const char *msg, va_list args)
+{
+ char *buffer;
+ const char *final;
+ size_t size = 256;
+ int n;
+
+ buffer = (char *)malloc(256);
+ while (buffer) {
+ n = vsnprintf(buffer, size, msg, args);
+ if (n >= 0 && (unsigned)n < size)
+ break;
+ size = n > 0 ? (unsigned)n + 1 : size * 2;
+ buffer = (char *)realloc(buffer, size);
+ }
+ final = buffer ? buffer : "";
+ subhelp_slog(severity, final);
+ if (buffer)
+ free(buffer);
+}
+
+void subhelp_slog(enum csri_logging_severity severity, const char *msg)
+{
+ if (logfunc)
+ logfunc(appdata, severity, msg);
+ else {
+ fprintf(stderr, msg);
+ fprintf(stderr, "\n");
+ }
+}
+
diff --git a/csri/subhelp/posix/openfile.c b/csri/subhelp/posix/openfile.c
new file mode 100644
index 000000000..1b2aad9aa
--- /dev/null
+++ b/csri/subhelp/posix/openfile.c
@@ -0,0 +1,82 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "acconf.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include
+#endif
+#include
+#include
+#ifdef HAVE_SYS_MMAN_H
+#include
+#endif
+#include
+#include
+#include
+
+#include "subhelp.h"
+#include
+
+csri_inst *subhelp_open_file(csri_rend *renderer,
+ csri_inst *(*memopenfunc)(csri_rend *renderer, const void *data,
+ size_t length, struct csri_openflag *flags),
+ const char *filename, struct csri_openflag *flags)
+{
+ csri_inst *rv = NULL;
+ void *data;
+ int fd;
+ struct stat st;
+ struct csri_openflag *err;
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1)
+ goto out_err;
+ if (fstat(fd, &st)
+ || !(data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE,
+ fd, 0))) {
+ close(fd);
+ goto out_err;
+ }
+
+ rv = memopenfunc(renderer, data, st.st_size, flags);
+
+ munmap(data, st.st_size);
+ close(fd);
+ return rv;
+
+out_err:
+ for (err = flags; err; err = err->next)
+ if (!strcmp(err->name, CSRI_EXT_OPENERR))
+ break;
+ if (err) {
+ struct csri_openerr_flag *errd = (struct csri_openerr_flag *)
+ err->data.otherval;
+ errd->flags = CSRI_OPENERR_FILLED | CSRI_OPENERR_ERRNO;
+ errd->posixerrno = errno;
+ }
+ return NULL;
+}
+
diff --git a/csri/subhelp/win32/openfile.c b/csri/subhelp/win32/openfile.c
new file mode 100644
index 000000000..5e177d91c
--- /dev/null
+++ b/csri/subhelp/win32/openfile.c
@@ -0,0 +1,84 @@
+/*****************************************************************************
+ * asa: portable digital subtitle renderer
+ *****************************************************************************
+ * Copyright (C) 2007 David Lamparter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#include
+#include
+
+#include "subhelp.h"
+#include
+
+csri_inst *subhelp_open_file(csri_rend *renderer,
+ csri_inst *(*memopenfunc)(csri_rend *renderer, const void *data,
+ size_t length, struct csri_openflag *flags),
+ const char *filename, struct csri_openflag *flags)
+{
+ csri_inst *rv = NULL;
+ void *data;
+ struct csri_openflag *err;
+ HANDLE file, mapping;
+ DWORD size;
+ int namesize;
+ wchar_t *namebuf;
+
+ namesize = MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
+ if (!namesize)
+ goto out_err;
+ namesize++;
+ namebuf = malloc(sizeof(wchar_t) * namesize);
+ MultiByteToWideChar(CP_UTF8, 0, filename, -1, namebuf, namesize);
+
+ file = CreateFileW(namebuf, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, 0, NULL);
+ free(namebuf);
+ if (file == INVALID_HANDLE_VALUE)
+ goto out_err;
+ size = GetFileSize(file, NULL);
+ if (size == INVALID_FILE_SIZE || !size)
+ goto out_closefile;
+ mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (!mapping)
+ goto out_closefile;
+ data = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, size);
+ if (!data)
+ goto out_closemap;
+
+ rv = memopenfunc(renderer, data, size, flags);
+
+ UnmapViewOfFile(data);
+ CloseHandle(mapping);
+ CloseHandle(file);
+ return rv;
+
+out_closemap:
+ CloseHandle(mapping);
+out_closefile:
+ CloseHandle(file);
+out_err:
+ for (err = flags; err; err = err->next)
+ if (!strcmp(err->name, CSRI_EXT_OPENERR))
+ break;
+ if (err) {
+ struct csri_openerr_flag *errd = err->data.otherval;
+ errd->flags = CSRI_OPENERR_FILLED | CSRI_OPENERR_WINERR;
+ errd->winerr = GetLastError();
+ }
+ return NULL;
+}
+