From cdd49b02b46dc2399354494626d1493b6208dd0c Mon Sep 17 00:00:00 2001
From: Amar Takhar <verm@aegisub.org>
Date: Thu, 6 Mar 2008 16:59:48 +0000
Subject: [PATCH] Bring CSRI into the repository fully, I'm not an advocate of
 this! but it's the best 'solution' for now.

Originally committed to SVN as r1915.
---
 csri/Doxyfile                          |  22 +
 csri/LICENSE                           |  31 +
 csri/Makefile.am                       |  12 +
 csri/ac/Makefile.am                    |   3 +
 csri/ac/csri.sln                       |  20 +
 csri/ac/subhelp.vcproj                 | 179 ++++++
 csri/acinclude.m4                      |  67 +++
 csri/backends/Makefile.am              |   4 +
 csri/backends/libass/Makefile.am       |   6 +
 csri/backends/libass/libass_csri.c     | 258 +++++++++
 csri/bootstrap                         |   4 +
 csri/configure.ac                      | 135 +++++
 csri/csri.pc.in                        |  10 +
 csri/csri.vcproj                       | 328 +++++++++++
 csri/csri_2008.vcproj                  | 327 +++++++++++
 csri/frontends/Makefile.am             |   4 +
 csri/frontends/avisynth25/Makefile.am  |  15 +
 csri/frontends/avisynth25/avisynth.cpp | 155 +++++
 csri/frontends/avisynth25/avisynth.h   | 754 +++++++++++++++++++++++++
 csri/frontends/cmdline/Makefile.am     |   6 +
 csri/frontends/cmdline/cmdmain.c       | 473 ++++++++++++++++
 csri/frontends/cmdline/render.c        | 240 ++++++++
 csri/frontends/cmdline/render.h        |  34 ++
 csri/include/Makefile.am               |   2 +
 csri/include/csri/csri.h               | 348 ++++++++++++
 csri/include/csri/fmtids.h             |  65 +++
 csri/include/csri/logging.h            |  79 +++
 csri/include/csri/openerr.h            | 124 ++++
 csri/include/csri/stream.h             | 143 +++++
 csri/include/subhelp.h                 | 114 ++++
 csri/include/visibility.h              |  43 ++
 csri/lib/Makefile.am                   |  14 +
 csri/lib/csrilib.h                     |  85 +++
 csri/lib/list.c                        | 148 +++++
 csri/lib/posix/csrilib_os.h            |  27 +
 csri/lib/posix/enumerate.c             | 199 +++++++
 csri/lib/win32/csrilib_os.h            |  25 +
 csri/lib/win32/enumerate.c             | 175 ++++++
 csri/lib/wrap.c                        | 118 ++++
 csri/subhelp/Makefile.am               |  10 +
 csri/subhelp/logging.c                 | 102 ++++
 csri/subhelp/posix/openfile.c          |  82 +++
 csri/subhelp/win32/openfile.c          |  84 +++
 43 files changed, 5074 insertions(+)
 create mode 100644 csri/Doxyfile
 create mode 100644 csri/LICENSE
 create mode 100644 csri/Makefile.am
 create mode 100644 csri/ac/Makefile.am
 create mode 100644 csri/ac/csri.sln
 create mode 100644 csri/ac/subhelp.vcproj
 create mode 100644 csri/acinclude.m4
 create mode 100644 csri/backends/Makefile.am
 create mode 100644 csri/backends/libass/Makefile.am
 create mode 100644 csri/backends/libass/libass_csri.c
 create mode 100755 csri/bootstrap
 create mode 100644 csri/configure.ac
 create mode 100644 csri/csri.pc.in
 create mode 100644 csri/csri.vcproj
 create mode 100644 csri/csri_2008.vcproj
 create mode 100644 csri/frontends/Makefile.am
 create mode 100644 csri/frontends/avisynth25/Makefile.am
 create mode 100644 csri/frontends/avisynth25/avisynth.cpp
 create mode 100644 csri/frontends/avisynth25/avisynth.h
 create mode 100644 csri/frontends/cmdline/Makefile.am
 create mode 100644 csri/frontends/cmdline/cmdmain.c
 create mode 100644 csri/frontends/cmdline/render.c
 create mode 100644 csri/frontends/cmdline/render.h
 create mode 100644 csri/include/Makefile.am
 create mode 100644 csri/include/csri/csri.h
 create mode 100644 csri/include/csri/fmtids.h
 create mode 100644 csri/include/csri/logging.h
 create mode 100644 csri/include/csri/openerr.h
 create mode 100644 csri/include/csri/stream.h
 create mode 100644 csri/include/subhelp.h
 create mode 100644 csri/include/visibility.h
 create mode 100644 csri/lib/Makefile.am
 create mode 100644 csri/lib/csrilib.h
 create mode 100644 csri/lib/list.c
 create mode 100644 csri/lib/posix/csrilib_os.h
 create mode 100644 csri/lib/posix/enumerate.c
 create mode 100644 csri/lib/win32/csrilib_os.h
 create mode 100644 csri/lib/win32/enumerate.c
 create mode 100644 csri/lib/wrap.c
 create mode 100644 csri/subhelp/Makefile.am
 create mode 100644 csri/subhelp/logging.c
 create mode 100644 csri/subhelp/posix/openfile.c
 create mode 100644 csri/subhelp/win32/openfile.c

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 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8,00"
+	Name="subhelp"
+	ProjectGUID="{870552FE-7B73-41AB-A7D9-475440F4731C}"
+	RootNamespace="subhelp"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="..\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Quelldateien"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\subhelp\win32\openfile.c"
+				>
+			</File>
+			<File
+				RelativePath="..\subhelp\logging.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Headerdateien"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\include\subhelp.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Ressourcendateien"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
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 <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <ass/ass.h>
+
+#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 <csri/csri.h>
+#include <csri/stream.h>
+#include <subhelp.h>
+
+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 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8,00"
+	Name="csri"
+	ProjectGUID="{4294BC27-91AC-4642-B5E1-042288478C2A}"
+	RootNamespace="csri"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="lib;lib/win32;include;../aegisub/win32"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+				CompileAs="1"
+				DisableSpecificWarnings="4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="../lib/csri_d.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="lib;lib/win32;include;../aegisub/win32"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				CompileAs="1"
+				DisableSpecificWarnings="4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				AdditionalOptions="/machine:x64"
+				OutputFile="../lib/csri_d_x64.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="lib;lib/win32;include;../aegisub/win32"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="../lib/csri.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="lib;lib/win32;include;../aegisub/win32"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				AdditionalOptions="/machine:x64"
+				OutputFile="../lib/csri_x64.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\lib\win32\enumerate.c"
+				>
+			</File>
+			<File
+				RelativePath=".\lib\list.c"
+				>
+			</File>
+			<File
+				RelativePath=".\subhelp\logging.c"
+				>
+			</File>
+			<File
+				RelativePath=".\lib\wrap.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\include\csri\csri.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
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 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="csri_2008"
+	ProjectGUID="{4294BC27-91AC-4642-B5E1-042288478C2A}"
+	RootNamespace="csri"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="lib;lib/win32;include;../aegisub/win32"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+				CompileAs="1"
+				DisableSpecificWarnings="4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="../lib/csri_d_x64.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="lib;lib/win32;include;../aegisub/win32"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				CompileAs="1"
+				DisableSpecificWarnings="4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="../lib/csri_d_x64.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="lib;lib/win32;include;../aegisub/win32"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="../lib/csri.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="lib;lib/win32;include;../aegisub/win32"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="../lib/csri_x64.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\lib\win32\enumerate.c"
+				>
+			</File>
+			<File
+				RelativePath=".\lib\list.c"
+				>
+			</File>
+			<File
+				RelativePath=".\subhelp\logging.c"
+				>
+			</File>
+			<File
+				RelativePath=".\lib\wrap.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\include\csri\csri.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
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 <windows.h>
+#include "avisynth.h"
+#include <stdio.h>
+
+#include <csri/csri.h>
+
+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 <windef.h>  
+
+// COM interface macros
+#include <objbase.h>
+
+
+// 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 <assert.h> interface
+#ifdef _MSC_VER
+  #include <crtdbg.h>
+#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 <assert.h>
+#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<array_size);
+    return (IsArray() && index>=0 && index<array_size) ? array[index] : *this;
+  }
+
+private:
+
+  short type;  // 'a'rray, 'c'lip, 'b'ool, 'i'nt, 'f'loat, 's'tring, 'v'oid, or 'l'ong
+  short array_size;
+  union {
+    IClip* clip;
+    bool boolean;
+    int integer;
+    float floating_pt;
+    const char* string;
+    const AVSValue* array;
+//    __int64 longlong;
+  };
+
+  void Assign(const AVSValue* src, bool init) {
+    if (src->IsClip() && 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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <math.h>
+
+#include <csri/csri.h>
+#include <csri/logging.h>
+#include <csri/openerr.h>
+#include <csri/stream.h>
+
+#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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <csri/csri.h>
+#include <csri/logging.h>
+
+#include "render.h"
+
+extern csri_rend *r;
+
+#ifdef HAVE_LIBPNG
+#include <png.h>
+
+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 <stddef.h>			/* 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.
+ *
+ * <b>Renderers must implement these functions as well.</b>
+ *
+ * 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$
+ *
+ * <b>THE SPECIFICATION OF THIS EXTENSION IS TENTATIVE
+ * AND NOT FINALIZED YET</b>
+ */
+
+#ifndef _CSRI_LOGGING_H
+/** \cond */
+#define _CSRI_LOGGING_H 20070119
+/** \endcond */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup logging csri.logging extension.
+ * <b>THE SPECIFICATION OF THIS EXTENSION IS TENTATIVE
+ * AND NOT FINALIZED YET</b>
+ */
+/*@{*/
+
+/** 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$
+ *
+ * <b>THE SPECIFICATION OF THIS EXTENSION IS TENTATIVE
+ * AND NOT FINALIZED YET</b>
+ */
+
+#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 <stdarg.h>
+#include <csri/csri.h>
+#include <csri/logging.h>
+
+/** \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 <csri/csri.h>
+#include <csri/stream.h>
+#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 <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <sys/types.h>
+
+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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <limits.h>
+#include <dlfcn.h>
+
+#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 <windows.h>
+
+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 <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#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 <string.h>
+
+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 <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "visibility.h"
+#include "subhelp.h"
+#include <csri/logging.h>
+
+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 : "<out of memory in logging function>";
+	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 <unistd.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include "subhelp.h"
+#include <csri/openerr.h>
+
+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 <windows.h>
+#include <string.h>
+
+#include "subhelp.h"
+#include <csri/openerr.h>
+
+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;
+}
+
-- 
GitLab