From eea30df7dbafd7301b1707bf5f69f22537ebda13 Mon Sep 17 00:00:00 2001
From: Thomas Goyne <plorkyeran@aegisub.org>
Date: Sat, 16 Jul 2011 03:36:28 +0000
Subject: [PATCH] Kill in-repo libass and ffms and clean up some old cruft in
 the configure script

Originally committed to SVN as r5480.
---
 aegisub/LICENCE                              |    6 -
 aegisub/Makefile                             |    8 -
 aegisub/Makefile.inc.in                      |   27 +-
 aegisub/Makefile.target                      |    2 +-
 aegisub/configure.in                         |  224 +-
 aegisub/libass/COPYING                       |   11 -
 aegisub/libass/Makefile                      |   24 -
 aegisub/libass/ass.c                         | 1238 -------
 aegisub/libass/ass.h                         |  383 --
 aegisub/libass/ass_bitmap.c                  |  531 ---
 aegisub/libass/ass_bitmap.h                  |   56 -
 aegisub/libass/ass_cache.c                   |  385 --
 aegisub/libass/ass_cache.h                   |  117 -
 aegisub/libass/ass_cache_template.h          |  122 -
 aegisub/libass/ass_drawing.c                 |  492 ---
 aegisub/libass/ass_drawing.h                 |   80 -
 aegisub/libass/ass_font.c                    |  701 ----
 aegisub/libass/ass_font.h                    |   66 -
 aegisub/libass/ass_fontconfig.c              |  531 ---
 aegisub/libass/ass_fontconfig.h              |   45 -
 aegisub/libass/ass_library.c                 |  146 -
 aegisub/libass/ass_library.h                 |   41 -
 aegisub/libass/ass_parse.c                   |  943 -----
 aegisub/libass/ass_parse.h                   |   38 -
 aegisub/libass/ass_render.c                  | 2538 -------------
 aegisub/libass/ass_render.h                  |  264 --
 aegisub/libass/ass_render_api.c              |  139 -
 aegisub/libass/ass_strtod.c                  |  249 --
 aegisub/libass/ass_types.h                   |  123 -
 aegisub/libass/ass_utils.c                   |  206 --
 aegisub/libass/ass_utils.h                   |  145 -
 aegisub/libass/config.h                      |   12 -
 aegisub/libass/help_mp.h                     |   55 -
 aegisub/libass/msvc/enca.h                   |  175 -
 aegisub/libass/msvc/inttypes.h               |  305 --
 aegisub/libass/msvc/stdint.h                 |  247 --
 aegisub/libass/msvc/strings.h                |    3 -
 aegisub/libass/msvc/unistd.h                 |    0
 aegisub/libass/wscript                       |   26 -
 aegisub/libffms/Makefile                     |   30 -
 aegisub/libffms/include/ffms.h               |  294 --
 aegisub/libffms/include/ffmscompat.h         |   85 -
 aegisub/libffms/src/core/audiosource.cpp     |  304 --
 aegisub/libffms/src/core/audiosource.h       |  162 -
 aegisub/libffms/src/core/config.h            |    0
 aegisub/libffms/src/core/ffms.cpp            |  469 ---
 aegisub/libffms/src/core/indexing.cpp        |  603 ----
 aegisub/libffms/src/core/indexing.h          |  195 -
 aegisub/libffms/src/core/lavfaudio.cpp       |   86 -
 aegisub/libffms/src/core/lavfindexer.cpp     |  160 -
 aegisub/libffms/src/core/lavfvideo.cpp       |  264 --
 aegisub/libffms/src/core/matroskaaudio.cpp   |   75 -
 aegisub/libffms/src/core/matroskaindexer.cpp |  160 -
 aegisub/libffms/src/core/matroskaparser.c    | 3371 ------------------
 aegisub/libffms/src/core/matroskaparser.h    |  396 --
 aegisub/libffms/src/core/matroskavideo.cpp   |  234 --
 aegisub/libffms/src/core/stdiostream.c       |  116 -
 aegisub/libffms/src/core/stdiostream.h       |   84 -
 aegisub/libffms/src/core/utils.cpp           |  758 ----
 aegisub/libffms/src/core/utils.h             |  232 --
 aegisub/libffms/src/core/videosource.cpp     |  296 --
 aegisub/libffms/src/core/videosource.h       |  151 -
 aegisub/libffms/src/core/wave64writer.cpp    |  112 -
 aegisub/libffms/src/core/wave64writer.h      |   57 -
 aegisub/libffms/wscript                      |   26 -
 aegisub/src/Makefile                         |   12 +-
 66 files changed, 27 insertions(+), 19409 deletions(-)
 delete mode 100644 aegisub/libass/COPYING
 delete mode 100644 aegisub/libass/Makefile
 delete mode 100644 aegisub/libass/ass.c
 delete mode 100644 aegisub/libass/ass.h
 delete mode 100644 aegisub/libass/ass_bitmap.c
 delete mode 100644 aegisub/libass/ass_bitmap.h
 delete mode 100644 aegisub/libass/ass_cache.c
 delete mode 100644 aegisub/libass/ass_cache.h
 delete mode 100644 aegisub/libass/ass_cache_template.h
 delete mode 100644 aegisub/libass/ass_drawing.c
 delete mode 100644 aegisub/libass/ass_drawing.h
 delete mode 100644 aegisub/libass/ass_font.c
 delete mode 100644 aegisub/libass/ass_font.h
 delete mode 100644 aegisub/libass/ass_fontconfig.c
 delete mode 100644 aegisub/libass/ass_fontconfig.h
 delete mode 100644 aegisub/libass/ass_library.c
 delete mode 100644 aegisub/libass/ass_library.h
 delete mode 100644 aegisub/libass/ass_parse.c
 delete mode 100644 aegisub/libass/ass_parse.h
 delete mode 100644 aegisub/libass/ass_render.c
 delete mode 100644 aegisub/libass/ass_render.h
 delete mode 100644 aegisub/libass/ass_render_api.c
 delete mode 100644 aegisub/libass/ass_strtod.c
 delete mode 100644 aegisub/libass/ass_types.h
 delete mode 100644 aegisub/libass/ass_utils.c
 delete mode 100644 aegisub/libass/ass_utils.h
 delete mode 100644 aegisub/libass/config.h
 delete mode 100644 aegisub/libass/help_mp.h
 delete mode 100644 aegisub/libass/msvc/enca.h
 delete mode 100644 aegisub/libass/msvc/inttypes.h
 delete mode 100644 aegisub/libass/msvc/stdint.h
 delete mode 100644 aegisub/libass/msvc/strings.h
 delete mode 100644 aegisub/libass/msvc/unistd.h
 delete mode 100644 aegisub/libass/wscript
 delete mode 100644 aegisub/libffms/Makefile
 delete mode 100644 aegisub/libffms/include/ffms.h
 delete mode 100644 aegisub/libffms/include/ffmscompat.h
 delete mode 100644 aegisub/libffms/src/core/audiosource.cpp
 delete mode 100644 aegisub/libffms/src/core/audiosource.h
 delete mode 100644 aegisub/libffms/src/core/config.h
 delete mode 100644 aegisub/libffms/src/core/ffms.cpp
 delete mode 100644 aegisub/libffms/src/core/indexing.cpp
 delete mode 100644 aegisub/libffms/src/core/indexing.h
 delete mode 100644 aegisub/libffms/src/core/lavfaudio.cpp
 delete mode 100644 aegisub/libffms/src/core/lavfindexer.cpp
 delete mode 100644 aegisub/libffms/src/core/lavfvideo.cpp
 delete mode 100644 aegisub/libffms/src/core/matroskaaudio.cpp
 delete mode 100644 aegisub/libffms/src/core/matroskaindexer.cpp
 delete mode 100644 aegisub/libffms/src/core/matroskaparser.c
 delete mode 100644 aegisub/libffms/src/core/matroskaparser.h
 delete mode 100644 aegisub/libffms/src/core/matroskavideo.cpp
 delete mode 100644 aegisub/libffms/src/core/stdiostream.c
 delete mode 100644 aegisub/libffms/src/core/stdiostream.h
 delete mode 100644 aegisub/libffms/src/core/utils.cpp
 delete mode 100644 aegisub/libffms/src/core/utils.h
 delete mode 100644 aegisub/libffms/src/core/videosource.cpp
 delete mode 100644 aegisub/libffms/src/core/videosource.h
 delete mode 100644 aegisub/libffms/src/core/wave64writer.cpp
 delete mode 100644 aegisub/libffms/src/core/wave64writer.h
 delete mode 100644 aegisub/libffms/wscript

diff --git a/aegisub/LICENCE b/aegisub/LICENCE
index db85fd642..0ae4666a7 100644
--- a/aegisub/LICENCE
+++ b/aegisub/LICENCE
@@ -33,12 +33,6 @@ covered by another license in the file itself.
 The following directories and file are covered by their respective licenses as 
 follows:
 
-libass/
- - ISC license. See libass/COPYING.
-
-libffms/
- - MIT license.
-
 src/boost/
  - Boost Software License Version 1.0 see src/boost/LICENSE_1_0.txt.
 
diff --git a/aegisub/Makefile b/aegisub/Makefile
index c12b44621..5244a7771 100644
--- a/aegisub/Makefile
+++ b/aegisub/Makefile
@@ -1,13 +1,5 @@
 include Makefile.inc
 
-ifeq (yes, $(WITH_LIBASS))
-SUBDIRS += libass
-endif
-
-ifeq (yes, $(HAVE_PROVIDER_FFMPEGSOURCE))
-SUBDIRS += libffms
-endif
-
 SUBDIRS += \
 	universalchardet \
 	libaegisub \
diff --git a/aegisub/Makefile.inc.in b/aegisub/Makefile.inc.in
index e26efc520..9795658ec 100644
--- a/aegisub/Makefile.inc.in
+++ b/aegisub/Makefile.inc.in
@@ -4,18 +4,15 @@
 HAVE_ALSA					= @with_alsa@
 HAVE_AUTO4_LUA				= @with_auto4_lua@
 HAVE_AUTOMATION				= @with_automation@
-HAVE_FFMPEG					= @agi_cv_with_ffmpeg@
 HAVE_HUNSPELL				= @with_hunspell@
 HAVE_OPENAL					= @with_openal@
 HAVE_OPENMP					= @with_openmp@
 HAVE_OSS					= @with_oss@
 HAVE_PORTAUDIO				= @with_portaudio@
-HAVE_PROVIDER_FFMPEGSOURCE	= @with_provider_ffmpegsource@
+HAVE_FFMS					= @with_ffms@
 HAVE_PULSEAUDIO				= @with_pulseaudio@
-WITH_EXTERNAL_LIBASS		= @with_external_libass@
-WITH_LIBASS					= @with_libass@
+HAVE_LIBASS					= @with_libass@
 FOUND_AUDIO_PLAYER			= @found_audio_player@
-FOUND_VIDEO_PROVIDER		= @found_video_provider@
 
 
 ###################
@@ -93,18 +90,12 @@ CPPFLAGS_WX				= @WX_CPPFLAGS@
 CFLAGS_FONTCONFIG		= @FONTCONFIG_CFLAGS@
 CFLAGS_FREETYPE			= @FREETYPE_CFLAGS@
 CFLAGS_GL				= @GL_CFLAGS@
-CFLAGS_FFMPEGSOURCE		= -I../libffms/include
+CFLAGS_FFMS				= @FFMS_CFLAGS@
 CFLAGS_HUNSPELL			= @HUNSPELL_CFLAGS@
 CFLAGS_ICONV			= @ICONV_CFLAGS@
-CFLAGS_LIBASS			= -I../libass
-#CFLAGS_LIBASS			= @LIBASS_CFLAGS@
-CFLAGS_LIBAVCODEC		= @LIBAVCODEC_CFLAGS@
-CFLAGS_LIBAVFORMAT		= @LIBAVFORMAT_CFLAGS@
-CFLAGS_LIBAVUTIL		= @LIBAVUTIL_CFLAGS@
+CFLAGS_LIBASS			= @LIBASS_CFLAGS@
 CFLAGS_LIBCURL			= @LIBCURL_CFLAGS@
-CFLAGS_LIBPOSTPROC		= @LIBPOSTPROC_CFLAGS@
 CFLAGS_LIBPULSE			= @LIBPULSE_CFLAGS@
-CFLAGS_LIBSWSCALE		= @LIBSWSCALE_CFLAGS@
 CFLAGS_LUA				= @LUA_CFLAGS@
 CFLAGS_OPENAL			= @OPENAL_CFLAGS@
 CFLAGS_PORTAUDIO		= @PORTAUDIO_CFLAGS@
@@ -116,18 +107,12 @@ LDFLAGS_ALSA			= @ALSA_LDFLAGS@
 LDFLAGS_FONTCONFIG		= @FONTCONFIG_LIBS@
 LDFLAGS_FREETYPE		= @FREETYPE_LIBS@
 LDFLAGS_GL				= @GL_LIBS@
-LDFLAGS_FFMPEGSOURCE	= ../libffms/libffmpegsource_aegisub.a
+LDFLAGS_FFMS			= @FFMS_LIBS@
 LDFLAGS_HUNSPELL		= @HUNSPELL_LIBS@
 LDFLAGS_ICONV			= @ICONV_LDFLAGS@
-LDFLAGS_LIBASS			= ../libass/libass_aegisub.a
-#LDFLAGS_LIBASS			= @LIBASS_LIBS@
-LDFLAGS_LIBAVCODEC		= @LIBAVCODEC_LIBS@
-LDFLAGS_LIBAVFORMAT		= @LIBAVFORMAT_LIBS@
-LDFLAGS_LIBAVUTIL		= @LIBAVUTIL_LIBS@
+LDFLAGS_LIBASS			= @LIBASS_LIBS@
 LDFLAGS_LIBCURL			= @LIBCURL_LIBS@
-LDFLAGS_LIBPOSTPROC		= @LIBPOSTPROC_LIBS@
 LDFLAGS_LIBPULSE		= @LIBPULSE_LIBS@
-LDFLAGS_LIBSWSCALE		= @LIBSWSCALE_LIBS@
 LDFLAGS_LUA				= @LUA_LDFLAGS@
 LDFLAGS_OPENAL			= @OPENAL_LIBS@
 LDFLAGS_PTHREAD			= @PTHREAD_LIBS@
diff --git a/aegisub/Makefile.target b/aegisub/Makefile.target
index e6e349312..e411122d0 100644
--- a/aegisub/Makefile.target
+++ b/aegisub/Makefile.target
@@ -121,7 +121,7 @@ $(SUBDIRS):
 	$(MAKE) -C $@ $(MAKECMDGOALS)
 
 # Set relations to ensure dependencies are built before their targets during parallel builds.
-src: universalchardet libass libffms tools libaegisub
+src: universalchardet tools libaegisub
 tests: libaegisub
 reporter: src
 command: libresrc
diff --git a/aegisub/configure.in b/aegisub/configure.in
index 8b89a097b..9eaf9f4f9 100644
--- a/aegisub/configure.in
+++ b/aegisub/configure.in
@@ -16,12 +16,6 @@ m4_define([aegisub_version_data], [aegisub_version_major.aegisub_version_minor])
 ###################
 # Required packages
 ###################
-m4_define([libavcodec_required_version], [52.27.0])  # (r18642)
-m4_define([libavformat_required_version], [52.32.0]) # (r18642)
-m4_define([libavutil_required_version], [50.3.0])    # (r18642)
-m4_define([libpostproc_required_version], [51.2.0])  # (r18642)
-m4_define([libswscale_required_version], [0.7.1])    # (r18642)
-
 m4_define([lua_auto4_required_version], [5.1])
 m4_define([portaudio_required_version], [19])
 m4_define([pulseaudio_required_version], [0.5])
@@ -31,6 +25,7 @@ m4_define([freetype_required_version], [9.7.0])
 m4_define([pkgconfig_required_version], [0.20])
 m4_define([wx_required_version], [2.9.0])
 m4_define([libass_required_version], [0.9.7])
+m4_define([ffms_required_version], [2.1.15])
 
 
 #######
@@ -681,154 +676,24 @@ AC_SUBST(with_oss)
 #########################
 # Video / Audio Providers
 #########################
+AC_ARG_WITH(ffms,[  --without-ffms          build without ffms2 A/V provider. (default: auto)], ffms_disabled="(disabled)")
 
-AC_ARG_WITH(ffmpeg, [  --without-ffmpeg        build without FFMPEG support.
-                          Disables FFMPEG and FFmpegSource A/V providers.
-                          (default: auto)], [ffmpeg_disabled="(disabled)"; with_ffmpeg="no"])
-
-if test "$with_ffmpeg" != "no"; then
-  PKG_CHECK_MODULES(LIBAVCODEC,  libavcodec >= libavcodec_required_version, [], [with_ffmpeg="no"])
-  PKG_CHECK_MODULES(LIBAVFORMAT, libavformat >= libavformat_required_version, [], [with_ffmpeg="no"])
-  PKG_CHECK_MODULES(LIBSWSCALE,  libswscale >=  libswscale_required_version, [], [with_ffmpeg="no"])
-  PKG_CHECK_MODULES(LIBAVUTIL,  libavutil >= libavutil_required_version, [], [with_ffmpeg="no"])
-fi
-
-if test "$with_ffmpeg" != "no" && test "$enable_old_ffmpeg" != "yes"; then
-  AC_AGI_COMPILE([FFMPEG], [ffmpeg], [$LIBSWSCALE_CFLAGS $LIBAVCODEC_CFLAGS $LIBAVFORMAT_CFLAGS $LIBAVUTIL_CFLAGS], [$LIBSWSCALE_LIBS $LIBAVCODEC_LIBS $LIBAVFORMAT_LIBS $LIBAVUTIL_LIBS],[
-#define __STDC_CONSTANT_MACROS
-extern "C" {
-#include <libavformat/avformat.h>
-#include <libavcodec/avcodec.h>
-#include <libswscale/swscale.h>
-}
-
-int main (void) {
-  AVFormatContext *fc = NULL;
-  AVCodec *c = NULL;
-  SwsContext *swsc = NULL;
-
-  av_register_all();
-  fc = avformat_alloc_context();
-  if (fc == NULL) {
-    printf("avformat failure\n");
-    return 1;
-  }
-  av_free(fc);
-                               
-  avcodec_init();
-  avcodec_register_all();
-  c = avcodec_find_decoder(CODEC_ID_PCM_S16LE);
-  if (c == NULL) {
-    printf("avcodec failure\n");
-    return 1;
-  }
-
-  swsc = sws_getContext(704, 480, PIX_FMT_RGB32, 704, 480, PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL);
-  if (swsc == NULL) {
-    printf("swscale failure\n");
-    return 1;
-  }
-  sws_freeContext(swsc);
-
-  return 0;
-} ])
-fi
-
-if test "$agi_cv_with_ffmpeg" = "no" && test "$with_ffmpeg" != "no"; then
-  AC_MSG_WARN([FFMPEG detected, but it doesn't work...])
-  with_ffmpeg="no"
-fi
-
-if test "$agi_cv_with_ffmpeg" = "yes" && test "$with_ffmpeg" != "no"; then
-  with_ffmpeg="yes"
-fi
-
-if test "$agi_cv_with_ffmpeg" = "no" || test "$with_ffmpeg" = "no"; then
-  ffmpegsource_provider_disabled="(disabled, requires FFMPEG)"
-  ffmpeg_provider_disabled="(disabled, requires FFMPEG)"
-  with_ffmpeg="no"
-fi
-
-AC_SUBST(agi_cv_with_ffmpeg)
-AC_SUBST(LIBAVFORMAT_LIBS)
-AC_SUBST(LIBAVFORMAT_CFLAGS)
-AC_SUBST(LIBAVCODEC_LIBS)
-AC_SUBST(LIBAVCODEC_CFLAGS)
-AC_SUBST(LIBSWSCALE_LIBS)
-AC_SUBST(LIBSWSCALE_CFLAGS)
-AC_SUBST(LIBAVUTIL_LIBS)
-AC_SUBST(LIBAVUTIL_CFLAGS)
-
-AC_ARG_WITH(provider-ffmpegsource, [  --without-provider-ffmpegsource
-                          build without FFmpegSource A/V provider.
-                          (default: auto)], ffmpegsource_provider_disabled="(disabled)", with_provider_ffmpegsource="yes")
-
-if test "$agi_cv_with_ffmpeg" = "yes" && test "$with_provider_ffmpegsource" = "yes"; then
-  PKG_CHECK_MODULES(LIBPOSTPROC,  libpostproc >= libpostproc_required_version, [], [with_libpostproc="no"])
-
-  AC_AGI_COMPILE([postproc], [postproc], [$LIBPOSTPROC_CFLAGS], [$LIBPOSTPROC_LIBS],[
-extern "C" {
-#define __STDC_CONSTANT_MACROS
-#include <libpostproc/postprocess.h>
-}
-
-int main (void) {
-  pp_context_t *PPContext = pp_get_context(704,480, 0);
-
-  if (!PPContext) return 1;
-  pp_free_context(PPContext);
-  return 0;
-} ])
-
-  if test "$agi_cv_with_postproc" = "yes"; then
-    found_video_provider="yes"
-    AC_DEFINE(WITH_FFMPEGSOURCE, 1, [Enable FFmpegSource2 Video Provider])
-  else
-    with_provider_ffmpegsource="no"
-  fi
-else
-  with_provider_ffmpegsource="no"
+if test "$with_ffms" != "no"; then
+  PKG_CHECK_MODULES(FFMS, ffms2 >= ffms_required_version, [with_ffms="yes"], [with_ffms="no"])
 fi
 
-AC_SUBST(with_provider_ffmpegsource)
-AC_SUBST(LIBPOSTPROC_LIBS)
-AC_SUBST(LIBPOSTPROC_CFLAGS)
-
+AC_SUBST(with_ffms)
 
 ###################
 # Subtitle Provider
 ###################
+AC_ARG_WITH(libass,[  --without-libass        build without libass support (default: auto)], libass_disabled="(disabled)")
 
-AC_ARG_ENABLE(libass, [  --disable-libass        disable libass support (default=enabled)], libass_disabled="(disabled)")
-AC_ARG_WITH(external-libass, [  --with-external-libass  link to external libass (default=use internal)])
-
-if test "$enable_libass" != "no"; then
-  if test "$with_external_libass" != "yes"; then
-    with_external_libass="no"
-
-    if test "$agi_cv_with_iconv" = "yes"; then
-      LIBASS_LIBS="-L../libass -lass_aegisub"
-      LIBASS_CFLAGS="-I../libass"
-      with_libass="yes"
-    else
-      AC_MSG_WARN([libiconv is required for libass support.])
-      with_libass="no"
-    fi
-  else
-    PKG_CHECK_MODULES(LIBASS, libass >= libass_required_version, [with_libass="yes"], [with_libass="no"])
-  fi
-fi
-
-if test "$with_libass" = "yes" || test "$enable_libass" != "no"; then
-  AC_DEFINE(WITH_LIBASS, 1, [Enable libass Subtitle Provider])
-else
-  with_libass="no"
+if test "$with_libass" != "no"; then
+  PKG_CHECK_MODULES(LIBASS, libass >= libass_required_version, [with_libass="yes"], [with_libass="no"])
 fi
 
 AC_SUBST(with_libass)
-AC_SUBST(with_external_libass)
-AC_SUBST(LIBASS_LIBS)
-AC_SUBST(LIBASS_CFLAGS)
 
 
 ###########
@@ -841,10 +706,7 @@ if test "$with_hunspell" != "no"; then
   AC_AGI_COMPILE([Hunspell], [hunspell], [$HUNSPELL_CFLAGS], [$HUNSPELL_LIBS],[
 #include <hunspell.hxx>
 int main(void) {
-  Hunspell *hunspell;
-  hunspell = new Hunspell(".", ".");
-  if (!hunspell) return 1;
-  return 0;
+  return !(new Hunspell(".", "."));
 }  ])
 fi
 
@@ -1163,44 +1025,10 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
 #   it above.
 ####################################################################
 
-AC_ARG_WITH(provider-video, [  --with-provider-video=(ffmpegsource)
-                          Default Video Provider. (default: ffmpegsource)])
-AC_ARG_WITH(provider-audio, [  --with-provider-audio=(ffmpegsource)
-                          Default Audio Provider. (default: ffmpegsource)])
 AC_ARG_WITH(player-audio, [  --with-player-audio=(alsa|openal|portaudio|pulseaudio)
                           Default Audio Player (default: Linux/ALSA,
                           Darwin/OpenAL, 1:*/OSS, 2:*/PortAudio.])
 
-# Default Video Provider.
-if ! test -z "$with_provider_video"; then
-    default_provider_video="$with_provider_video"
-else
-  if test "$with_provider_ffmpegsource" = "yes"; then
-    default_provider_video="ffmpegsource"
-  fi
-fi
-AC_DEFINE_UNQUOTED([DEFAULT_PROVIDER_VIDEO], ["$default_provider_video"], [Default Video Provider.])
-
-# Default Audio Provider.
-if ! test -z "$with_provider_audio"; then
-    default_provider_audio="$with_provider_audio"
-else
-  if test "$with_provider_ffmpegsource" = "yes"; then
-    default_provider_audio="ffmpegsource"
-  fi
-fi
-AC_DEFINE_UNQUOTED([DEFAULT_PROVIDER_AUDIO], ["$default_provider_audio"], [Default Video Provider.])
-
-# Default Subtitle Provider.
-if ! test -z "$with_provider_subtitle"; then
-    default_provider_subtitle="$with_provider_subtitle"
-else
-  if test "$with_libass" = "yes"; then
-    default_provider_subtitle="libass"
-  fi
-fi
-AC_DEFINE_UNQUOTED([DEFAULT_PROVIDER_SUBTITLE], ["$default_provider_subtitle"], [Default Subtitle Provider.])
-
 # Default audio player.
 if ! test -z "$with_player_audio"; then
     default_player_audio="$with_player_audio"
@@ -1221,31 +1049,15 @@ AC_DEFINE_UNQUOTED([DEFAULT_PLAYER_AUDIO], ["$default_player_audio"], [Default a
 
 
 # Set some friendly strings if some of the above aren't detected.
-if test -z "$default_provider_video"; then
-  default_provider_video="NONE (requires ffmpeg)"
-fi
-
-if test -z "$default_provider_audio"; then
-  default_provider_audio="NONE (requires ffmpeg)"
-fi
-
-if test -z "$default_provider_subtitle"; then
-  default_provider_subtitle="NONE"
-fi
-
 if test -z "$default_player_audio"; then
   default_player_audio="NONE"
 fi
 
 
-
-
 ###############
 # Misc settings 
 ###############
 AC_SUBST(found_audio_player)
-AC_SUBST(found_audio_provider)
-AC_SUBST(found_video_provider)
 
 # Files that need substitution.
 AC_CONFIG_FILES([
@@ -1273,7 +1085,7 @@ if test -z "$found_audio_player"; then
   ])
 fi
 
-if test -z "$found_video_provider"; then
+if test "$with_ffms" != "yes"; then
   AC_MSG_NOTICE([
 
 ***********************************************************************
@@ -1284,8 +1096,8 @@ if test -z "$found_video_provider"; then
 * virtual video clip with subtitles overlaid.
 * Currently we only support one video/audio provider on non-Windows
 * systems:
-*  - FFmpeg (libavcodec + libavformat)
-*    * http://ffmpeg.mplayerhq.hu/
+*  - FFMS2
+*    * http://code.google.com/p/ffmpegsource/
 ***********************************************************************
   ])
 fi
@@ -1300,9 +1112,6 @@ Configure settings
   LDFLAGS                $LDFLAGS
 
 Default Settings
-  Video Provider:        $default_provider_video
-  Audio Provider:        $default_provider_audio
-  Subtitle Provider:     $default_provider_subtitle
   Audio Player:          $default_player_audio
 
 Scripting Engines
@@ -1315,16 +1124,11 @@ Audio Players
   PortAudio:             $with_portaudio $portaudio_disabled
   PulseAudio:            $with_pulseaudio $pulseaudio_disabled
 
-A/V Support
-  FFMPEG:                $with_ffmpeg $ffmpeg_disabled
-                         (required for video providers)
-
 A/V Providers
-  FFmpegSource:          $with_provider_ffmpegsource $ffmpegsource_provider_disabled
+  FFMS2:                 $with_ffms $ffms_disabled
 
 Subtitle Providers:
-  libASS                 $with_libass $libass_disabled $libass_default
-                         (both require iconv and fontconfig)
+  libass                 $with_libass $libass_disabled
 
 Misc Packages
   Hunspell:              $with_hunspell $with_hunspell_version $hunspell_disabled
diff --git a/aegisub/libass/COPYING b/aegisub/libass/COPYING
deleted file mode 100644
index 8351a30e3..000000000
--- a/aegisub/libass/COPYING
+++ /dev/null
@@ -1,11 +0,0 @@
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/aegisub/libass/Makefile b/aegisub/libass/Makefile
deleted file mode 100644
index fd44720b6..000000000
--- a/aegisub/libass/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-include ../Makefile.inc
-
-CXXFLAGS += -DCONFIG_ICONV -DCONFIG_FONTCONFIG $(CFLAGS_FREETYPE) $(CFLAGS_ICONV) $(CFLAGS_FONTCONFIG)
-
-LIB = libass_aegisub.a
-
-SRC = \
-	ass.c \
-	ass_bitmap.c \
-	ass_cache.c \
-	ass_drawing.c \
-	ass_font.c \
-	ass_fontconfig.c \
-	ass_library.c \
-	ass_parse.c \
-	ass_render.c \
-	ass_render_api.c \
-	ass_strtod.c \
-	ass_utils.c
-
-HEADER = *.h
-
-include ../Makefile.target
--include *.d
diff --git a/aegisub/libass/ass.c b/aegisub/libass/ass.c
deleted file mode 100644
index 368377251..000000000
--- a/aegisub/libass/ass.c
+++ /dev/null
@@ -1,1238 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <assert.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <inttypes.h>
-
-#ifdef CONFIG_ICONV
-#include <iconv.h>
-#endif
-
-#include "ass.h"
-#include "ass_utils.h"
-#include "ass_library.h"
-
-#define ass_atof(STR) (ass_strtod((STR),NULL))
-
-typedef enum {
-    PST_UNKNOWN = 0,
-    PST_INFO,
-    PST_STYLES,
-    PST_EVENTS,
-    PST_FONTS
-} ParserState;
-
-struct parser_priv {
-    ParserState state;
-    char *fontname;
-    char *fontdata;
-    int fontdata_size;
-    int fontdata_used;
-};
-
-#define ASS_STYLES_ALLOC 20
-#define ASS_EVENTS_ALLOC 200
-
-void ass_free_track(ASS_Track *track)
-{
-    int i;
-
-    if (track->parser_priv) {
-        free(track->parser_priv->fontname);
-        free(track->parser_priv->fontdata);
-        free(track->parser_priv);
-    }
-    free(track->style_format);
-    free(track->event_format);
-    if (track->styles) {
-        for (i = 0; i < track->n_styles; ++i)
-            ass_free_style(track, i);
-    }
-    free(track->styles);
-    if (track->events) {
-        for (i = 0; i < track->n_events; ++i)
-            ass_free_event(track, i);
-    }
-    free(track->events);
-    free(track->name);
-    free(track);
-}
-
-/// \brief Allocate a new style struct
-/// \param track track
-/// \return style id
-int ass_alloc_style(ASS_Track *track)
-{
-    int sid;
-
-    assert(track->n_styles <= track->max_styles);
-
-    if (track->n_styles == track->max_styles) {
-        track->max_styles += ASS_STYLES_ALLOC;
-        track->styles =
-            (ASS_Style *) realloc(track->styles,
-                                  sizeof(ASS_Style) *
-                                  track->max_styles);
-    }
-
-    sid = track->n_styles++;
-    memset(track->styles + sid, 0, sizeof(ASS_Style));
-    return sid;
-}
-
-/// \brief Allocate a new event struct
-/// \param track track
-/// \return event id
-int ass_alloc_event(ASS_Track *track)
-{
-    int eid;
-
-    assert(track->n_events <= track->max_events);
-
-    if (track->n_events == track->max_events) {
-        track->max_events += ASS_EVENTS_ALLOC;
-        track->events =
-            (ASS_Event *) realloc(track->events,
-                                  sizeof(ASS_Event) *
-                                  track->max_events);
-    }
-
-    eid = track->n_events++;
-    memset(track->events + eid, 0, sizeof(ASS_Event));
-    return eid;
-}
-
-void ass_free_event(ASS_Track *track, int eid)
-{
-    ASS_Event *event = track->events + eid;
-
-    free(event->Name);
-    free(event->Effect);
-    free(event->Text);
-    free(event->render_priv);
-}
-
-void ass_free_style(ASS_Track *track, int sid)
-{
-    ASS_Style *style = track->styles + sid;
-
-    free(style->Name);
-    free(style->FontName);
-}
-
-// ==============================================================================================
-
-static void skip_spaces(char **str)
-{
-    char *p = *str;
-    while ((*p == ' ') || (*p == '\t'))
-        ++p;
-    *str = p;
-}
-
-static void rskip_spaces(char **str, char *limit)
-{
-    char *p = *str;
-    while ((p >= limit) && ((*p == ' ') || (*p == '\t')))
-        --p;
-    *str = p;
-}
-
-/**
- * \brief find style by name
- * \param track track
- * \param name style name
- * \return index in track->styles
- * Returnes 0 if no styles found => expects at least 1 style.
- * Parsing code always adds "Default" style in the end.
- */
-static int lookup_style(ASS_Track *track, char *name)
-{
-    int i;
-    if (*name == '*')
-        ++name;                 // FIXME: what does '*' really mean ?
-    for (i = track->n_styles - 1; i >= 0; --i) {
-        // FIXME: mb strcasecmp ?
-        if (strcmp(track->styles[i].Name, name) == 0)
-            return i;
-    }
-    i = track->default_style;
-    ass_msg(track->library, MSGL_WARN,
-            "[%p]: Warning: no style named '%s' found, using '%s'",
-            track, name, track->styles[i].Name);
-    return i;                   // use the first style
-}
-
-static uint32_t string2color(ASS_Library *library, char *p)
-{
-    uint32_t tmp;
-    (void) strtocolor(library, &p, &tmp, 0);
-    return tmp;
-}
-
-static long long string2timecode(ASS_Library *library, char *p)
-{
-    unsigned h, m, s, ms;
-    long long tm;
-    int res = sscanf(p, "%1d:%2d:%2d.%2d", &h, &m, &s, &ms);
-    if (res < 4) {
-        ass_msg(library, MSGL_WARN, "Bad timestamp");
-        return 0;
-    }
-    tm = ((h * 60 + m) * 60 + s) * 1000 + ms * 10;
-    return tm;
-}
-
-/**
- * \brief converts numpad-style align to align.
- */
-static int numpad2align(int val)
-{
-    int res, v;
-    v = (val - 1) / 3;          // 0, 1 or 2 for vertical alignment
-    if (v != 0)
-        v = 3 - v;
-    res = ((val - 1) % 3) + 1;  // horizontal alignment
-    res += v * 4;
-    return res;
-}
-
-#define NEXT(str,token) \
-	token = next_token(&str); \
-	if (!token) break;
-
-#define ANYVAL(name,func) \
-	} else if (strcasecmp(tname, #name) == 0) { \
-		target->name = func(token); \
-		ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token);
-
-#define STRVAL(name) \
-	} else if (strcasecmp(tname, #name) == 0) { \
-		if (target->name != NULL) free(target->name); \
-		target->name = strdup(token); \
-		ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token);
-
-#define COLORVAL(name) \
-	} else if (strcasecmp(tname, #name) == 0) { \
-		target->name = string2color(track->library, token); \
-		ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token);
-
-#define INTVAL(name) ANYVAL(name,atoi)
-#define FPVAL(name) ANYVAL(name,ass_atof)
-#define TIMEVAL(name) \
-	} else if (strcasecmp(tname, #name) == 0) { \
-		target->name = string2timecode(track->library, token); \
-		ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token);
-
-#define STYLEVAL(name) \
-	} else if (strcasecmp(tname, #name) == 0) { \
-		target->name = lookup_style(track, token); \
-		ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token);
-
-#define ALIAS(alias,name) \
-	if (strcasecmp(tname, #alias) == 0) {tname = #name;}
-
-static char *next_token(char **str)
-{
-    char *p = *str;
-    char *start;
-    skip_spaces(&p);
-    if (*p == '\0') {
-        *str = p;
-        return 0;
-    }
-    start = p;                  // start of the token
-    for (; (*p != '\0') && (*p != ','); ++p) {
-    }
-    if (*p == '\0') {
-        *str = p;               // eos found, str will point to '\0' at exit
-    } else {
-        *p = '\0';
-        *str = p + 1;           // ',' found, str will point to the next char (beginning of the next token)
-    }
-    --p;                        // end of current token
-    rskip_spaces(&p, start);
-    if (p < start)
-        p = start;              // empty token
-    else
-        ++p;                    // the first space character, or '\0'
-    *p = '\0';
-    return start;
-}
-
-/**
- * \brief Parse the tail of Dialogue line
- * \param track track
- * \param event parsed data goes here
- * \param str string to parse, zero-terminated
- * \param n_ignored number of format options to skip at the beginning
-*/
-static int process_event_tail(ASS_Track *track, ASS_Event *event,
-                              char *str, int n_ignored)
-{
-    char *token;
-    char *tname;
-    char *p = str;
-    int i;
-    ASS_Event *target = event;
-
-    char *format = strdup(track->event_format);
-    char *q = format;           // format scanning pointer
-
-    if (track->n_styles == 0) {
-        // add "Default" style to the end
-        // will be used if track does not contain a default style (or even does not contain styles at all)
-        int sid = ass_alloc_style(track);
-        track->styles[sid].Name = strdup("Default");
-        track->styles[sid].FontName = strdup("Arial");
-    }
-
-    for (i = 0; i < n_ignored; ++i) {
-        NEXT(q, tname);
-    }
-
-    while (1) {
-        NEXT(q, tname);
-        if (strcasecmp(tname, "Text") == 0) {
-            char *last;
-            event->Text = strdup(p);
-            if (*event->Text != 0) {
-                last = event->Text + strlen(event->Text) - 1;
-                if (last >= event->Text && *last == '\r')
-                    *last = 0;
-            }
-            ass_msg(track->library, MSGL_DBG2, "Text = %s", event->Text);
-            event->Duration -= event->Start;
-            free(format);
-            return 0;           // "Text" is always the last
-        }
-        NEXT(p, token);
-
-        ALIAS(End, Duration)    // temporarily store end timecode in event->Duration
-        if (0) {            // cool ;)
-            INTVAL(Layer)
-            STYLEVAL(Style)
-            STRVAL(Name)
-            STRVAL(Effect)
-            INTVAL(MarginL)
-            INTVAL(MarginR)
-            INTVAL(MarginV)
-            TIMEVAL(Start)
-            TIMEVAL(Duration)
-        }
-    }
-    free(format);
-    return 1;
-}
-
-/**
- * \brief Parse command line style overrides (--ass-force-style option)
- * \param track track to apply overrides to
- * The format for overrides is [StyleName.]Field=Value
- */
-void ass_process_force_style(ASS_Track *track)
-{
-    char **fs, *eq, *dt, *style, *tname, *token;
-    ASS_Style *target;
-    int sid;
-    char **list = track->library->style_overrides;
-
-    if (!list)
-        return;
-
-    for (fs = list; *fs; ++fs) {
-        eq = strrchr(*fs, '=');
-        if (!eq)
-            continue;
-        *eq = '\0';
-        token = eq + 1;
-
-        if (!strcasecmp(*fs, "PlayResX"))
-            track->PlayResX = atoi(token);
-        else if (!strcasecmp(*fs, "PlayResY"))
-            track->PlayResY = atoi(token);
-        else if (!strcasecmp(*fs, "Timer"))
-            track->Timer = ass_atof(token);
-        else if (!strcasecmp(*fs, "WrapStyle"))
-            track->WrapStyle = atoi(token);
-        else if (!strcasecmp(*fs, "ScaledBorderAndShadow"))
-            track->ScaledBorderAndShadow = parse_bool(token);
-        else if (!strcasecmp(*fs, "Kerning"))
-            track->Kerning = parse_bool(token);
-
-        dt = strrchr(*fs, '.');
-        if (dt) {
-            *dt = '\0';
-            style = *fs;
-            tname = dt + 1;
-        } else {
-            style = NULL;
-            tname = *fs;
-        }
-        for (sid = 0; sid < track->n_styles; ++sid) {
-            if (style == NULL
-                || strcasecmp(track->styles[sid].Name, style) == 0) {
-                target = track->styles + sid;
-                if (0) {
-                    STRVAL(FontName)
-                    COLORVAL(PrimaryColour)
-                    COLORVAL(SecondaryColour)
-                    COLORVAL(OutlineColour)
-                    COLORVAL(BackColour)
-                    FPVAL(FontSize)
-                    INTVAL(Bold)
-                    INTVAL(Italic)
-                    INTVAL(Underline)
-                    INTVAL(StrikeOut)
-                    FPVAL(Spacing)
-                    INTVAL(Angle)
-                    INTVAL(BorderStyle)
-                    INTVAL(Alignment)
-                    INTVAL(MarginL)
-                    INTVAL(MarginR)
-                    INTVAL(MarginV)
-                    INTVAL(Encoding)
-                    FPVAL(ScaleX)
-                    FPVAL(ScaleY)
-                    FPVAL(Outline)
-                    FPVAL(Shadow)
-                }
-            }
-        }
-        *eq = '=';
-        if (dt)
-            *dt = '.';
-    }
-}
-
-/**
- * \brief Parse the Style line
- * \param track track
- * \param str string to parse, zero-terminated
- * Allocates a new style struct.
-*/
-static int process_style(ASS_Track *track, char *str)
-{
-
-    char *token;
-    char *tname;
-    char *p = str;
-    char *format;
-    char *q;                    // format scanning pointer
-    int sid;
-    ASS_Style *style;
-    ASS_Style *target;
-
-    if (!track->style_format) {
-        // no style format header
-        // probably an ancient script version
-        if (track->track_type == TRACK_TYPE_SSA)
-            track->style_format =
-                strdup
-                ("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour,"
-                 "TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline,"
-                 "Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding");
-        else
-            track->style_format =
-                strdup
-                ("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour,"
-                 "OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut,"
-                 "ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow,"
-                 "Alignment, MarginL, MarginR, MarginV, Encoding");
-    }
-
-    q = format = strdup(track->style_format);
-
-    ass_msg(track->library, MSGL_V, "[%p] Style: %s", track, str);
-
-    sid = ass_alloc_style(track);
-
-    style = track->styles + sid;
-    target = style;
-
-    // fill style with some default values
-    style->ScaleX = 100.;
-    style->ScaleY = 100.;
-
-    while (1) {
-        NEXT(q, tname);
-        NEXT(p, token);
-
-        if (0) {                // cool ;)
-            STRVAL(Name)
-            if ((strcmp(target->Name, "Default") == 0)
-                || (strcmp(target->Name, "*Default") == 0))
-            track->default_style = sid;
-            STRVAL(FontName)
-            COLORVAL(PrimaryColour)
-            COLORVAL(SecondaryColour)
-            COLORVAL(OutlineColour) // TertiaryColor
-            COLORVAL(BackColour)
-            // SSA uses BackColour for both outline and shadow
-            // this will destroy SSA's TertiaryColour, but i'm not going to use it anyway
-            if (track->track_type == TRACK_TYPE_SSA)
-                target->OutlineColour = target->BackColour;
-            FPVAL(FontSize)
-            INTVAL(Bold)
-            INTVAL(Italic)
-            INTVAL(Underline)
-            INTVAL(StrikeOut)
-            FPVAL(Spacing)
-            INTVAL(Angle)
-            INTVAL(BorderStyle)
-            INTVAL(Alignment)
-            if (track->track_type == TRACK_TYPE_ASS)
-                target->Alignment = numpad2align(target->Alignment);
-            INTVAL(MarginL)
-            INTVAL(MarginR)
-            INTVAL(MarginV)
-            INTVAL(Encoding)
-            FPVAL(ScaleX)
-            FPVAL(ScaleY)
-            FPVAL(Outline)
-            FPVAL(Shadow)
-        }
-    }
-    style->ScaleX /= 100.;
-    style->ScaleY /= 100.;
-    style->Bold = !!style->Bold;
-    style->Italic = !!style->Italic;
-    style->Underline = !!style->Underline;
-    if (!style->Name)
-        style->Name = strdup("Default");
-    if (!style->FontName)
-        style->FontName = strdup("Arial");
-    free(format);
-    return 0;
-
-}
-
-static int process_styles_line(ASS_Track *track, char *str)
-{
-    if (!strncmp(str, "Format:", 7)) {
-        char *p = str + 7;
-        skip_spaces(&p);
-        track->style_format = strdup(p);
-        ass_msg(track->library, MSGL_DBG2, "Style format: %s",
-               track->style_format);
-    } else if (!strncmp(str, "Style:", 6)) {
-        char *p = str + 6;
-        skip_spaces(&p);
-        process_style(track, p);
-    }
-    return 0;
-}
-
-static int process_info_line(ASS_Track *track, char *str)
-{
-    if (!strncmp(str, "PlayResX:", 9)) {
-        track->PlayResX = atoi(str + 9);
-    } else if (!strncmp(str, "PlayResY:", 9)) {
-        track->PlayResY = atoi(str + 9);
-    } else if (!strncmp(str, "Timer:", 6)) {
-        track->Timer = ass_atof(str + 6);
-    } else if (!strncmp(str, "WrapStyle:", 10)) {
-        track->WrapStyle = atoi(str + 10);
-    } else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) {
-        track->ScaledBorderAndShadow = parse_bool(str + 22);
-    } else if (!strncmp(str, "Kerning:", 8)) {
-        track->Kerning = parse_bool(str + 8);
-    }
-    return 0;
-}
-
-static void event_format_fallback(ASS_Track *track)
-{
-    track->parser_priv->state = PST_EVENTS;
-    if (track->track_type == TRACK_TYPE_SSA)
-        track->event_format = strdup("Format: Marked, Start, End, Style, "
-            "Name, MarginL, MarginR, MarginV, Effect, Text");
-    else
-        track->event_format = strdup("Format: Layer, Start, End, Style, "
-            "Actor, MarginL, MarginR, MarginV, Effect, Text");
-    ass_msg(track->library, MSGL_V,
-            "No event format found, using fallback");
-}
-
-static int process_events_line(ASS_Track *track, char *str)
-{
-    if (!strncmp(str, "Format:", 7)) {
-        char *p = str + 7;
-        skip_spaces(&p);
-        free(track->event_format);
-        track->event_format = strdup(p);
-        ass_msg(track->library, MSGL_DBG2, "Event format: %s", track->event_format);
-    } else if (!strncmp(str, "Dialogue:", 9)) {
-        // This should never be reached for embedded subtitles.
-        // They have slightly different format and are parsed in ass_process_chunk,
-        // called directly from demuxer
-        int eid;
-        ASS_Event *event;
-
-        str += 9;
-        skip_spaces(&str);
-
-        eid = ass_alloc_event(track);
-        event = track->events + eid;
-
-        // We can't parse events with event_format
-        if (!track->event_format)
-            event_format_fallback(track);
-
-        process_event_tail(track, event, str, 0);
-    } else {
-        ass_msg(track->library, MSGL_V, "Not understood: '%.30s'", str);
-    }
-    return 0;
-}
-
-// Copied from mkvtoolnix
-static unsigned char *decode_chars(unsigned char c1, unsigned char c2,
-                                   unsigned char c3, unsigned char c4,
-                                   unsigned char *dst, int cnt)
-{
-    uint32_t value;
-    unsigned char bytes[3];
-    int i;
-
-    value =
-        ((c1 - 33) << 18) + ((c2 - 33) << 12) + ((c3 - 33) << 6) + (c4 -
-                                                                    33);
-    bytes[2] = value & 0xff;
-    bytes[1] = (value & 0xff00) >> 8;
-    bytes[0] = (value & 0xff0000) >> 16;
-
-    for (i = 0; i < cnt; ++i)
-        *dst++ = bytes[i];
-    return dst;
-}
-
-static int decode_font(ASS_Track *track)
-{
-    unsigned char *p;
-    unsigned char *q;
-    int i;
-    int size;                   // original size
-    int dsize;                  // decoded size
-    unsigned char *buf = 0;
-
-    ass_msg(track->library, MSGL_V, "Font: %d bytes encoded data",
-            track->parser_priv->fontdata_used);
-    size = track->parser_priv->fontdata_used;
-    if (size % 4 == 1) {
-        ass_msg(track->library, MSGL_ERR, "Bad encoded data size");
-        goto error_decode_font;
-    }
-    buf = malloc(size / 4 * 3 + 2);
-    q = buf;
-    for (i = 0, p = (unsigned char *) track->parser_priv->fontdata;
-         i < size / 4; i++, p += 4) {
-        q = decode_chars(p[0], p[1], p[2], p[3], q, 3);
-    }
-    if (size % 4 == 2) {
-        q = decode_chars(p[0], p[1], 0, 0, q, 1);
-    } else if (size % 4 == 3) {
-        q = decode_chars(p[0], p[1], p[2], 0, q, 2);
-    }
-    dsize = q - buf;
-    assert(dsize <= size / 4 * 3 + 2);
-
-    if (track->library->extract_fonts) {
-        ass_add_font(track->library, track->parser_priv->fontname,
-                     (char *) buf, dsize);
-    }
-
-error_decode_font:
-    free(buf);
-    free(track->parser_priv->fontname);
-    free(track->parser_priv->fontdata);
-    track->parser_priv->fontname = 0;
-    track->parser_priv->fontdata = 0;
-    track->parser_priv->fontdata_size = 0;
-    track->parser_priv->fontdata_used = 0;
-    return 0;
-}
-
-static int process_fonts_line(ASS_Track *track, char *str)
-{
-    int len;
-
-    if (!strncmp(str, "fontname:", 9)) {
-        char *p = str + 9;
-        skip_spaces(&p);
-        if (track->parser_priv->fontname) {
-            decode_font(track);
-        }
-        track->parser_priv->fontname = strdup(p);
-        ass_msg(track->library, MSGL_V, "Fontname: %s",
-               track->parser_priv->fontname);
-        return 0;
-    }
-
-    if (!track->parser_priv->fontname) {
-        ass_msg(track->library, MSGL_V, "Not understood: '%s'", str);
-        return 0;
-    }
-
-    len = strlen(str);
-    if (len > 80) {
-        ass_msg(track->library, MSGL_WARN, "Font line too long: %d, %s",
-                len, str);
-        return 0;
-    }
-    if (track->parser_priv->fontdata_used + len >
-        track->parser_priv->fontdata_size) {
-        track->parser_priv->fontdata_size += 100 * 1024;
-        track->parser_priv->fontdata =
-            realloc(track->parser_priv->fontdata,
-                    track->parser_priv->fontdata_size);
-    }
-    memcpy(track->parser_priv->fontdata + track->parser_priv->fontdata_used,
-           str, len);
-    track->parser_priv->fontdata_used += len;
-
-    return 0;
-}
-
-/**
- * \brief Parse a header line
- * \param track track
- * \param str string to parse, zero-terminated
-*/
-static int process_line(ASS_Track *track, char *str)
-{
-    if (!strncasecmp(str, "[Script Info]", 13)) {
-        track->parser_priv->state = PST_INFO;
-    } else if (!strncasecmp(str, "[V4 Styles]", 11)) {
-        track->parser_priv->state = PST_STYLES;
-        track->track_type = TRACK_TYPE_SSA;
-    } else if (!strncasecmp(str, "[V4+ Styles]", 12)) {
-        track->parser_priv->state = PST_STYLES;
-        track->track_type = TRACK_TYPE_ASS;
-    } else if (!strncasecmp(str, "[Events]", 8)) {
-        track->parser_priv->state = PST_EVENTS;
-    } else if (!strncasecmp(str, "[Fonts]", 7)) {
-        track->parser_priv->state = PST_FONTS;
-    } else {
-        switch (track->parser_priv->state) {
-        case PST_INFO:
-            process_info_line(track, str);
-            break;
-        case PST_STYLES:
-            process_styles_line(track, str);
-            break;
-        case PST_EVENTS:
-            process_events_line(track, str);
-            break;
-        case PST_FONTS:
-            process_fonts_line(track, str);
-            break;
-        default:
-            break;
-        }
-    }
-
-    // there is no explicit end-of-font marker in ssa/ass
-    if ((track->parser_priv->state != PST_FONTS)
-        && (track->parser_priv->fontname))
-        decode_font(track);
-
-    return 0;
-}
-
-static int process_text(ASS_Track *track, char *str)
-{
-    char *p = str;
-    while (1) {
-        char *q;
-        while (1) {
-            if ((*p == '\r') || (*p == '\n'))
-                ++p;
-            else if (p[0] == '\xef' && p[1] == '\xbb' && p[2] == '\xbf')
-                p += 3;         // U+FFFE (BOM)
-            else
-                break;
-        }
-        for (q = p; ((*q != '\0') && (*q != '\r') && (*q != '\n')); ++q) {
-        };
-        if (q == p)
-            break;
-        if (*q != '\0')
-            *(q++) = '\0';
-        process_line(track, p);
-        if (*q == '\0')
-            break;
-        p = q;
-    }
-    return 0;
-}
-
-/**
- * \brief Process a chunk of subtitle stream data.
- * \param track track
- * \param data string to parse
- * \param size length of data
-*/
-void ass_process_data(ASS_Track *track, char *data, int size)
-{
-    char *str = malloc(size + 1);
-
-    memcpy(str, data, size);
-    str[size] = '\0';
-
-    ass_msg(track->library, MSGL_V, "Event: %s", str);
-    process_text(track, str);
-    free(str);
-}
-
-/**
- * \brief Process CodecPrivate section of subtitle stream
- * \param track track
- * \param data string to parse
- * \param size length of data
- CodecPrivate section contains [Stream Info] and [V4+ Styles] ([V4 Styles] for SSA) sections
-*/
-void ass_process_codec_private(ASS_Track *track, char *data, int size)
-{
-    ass_process_data(track, data, size);
-
-    // probably an mkv produced by ancient mkvtoolnix
-    // such files don't have [Events] and Format: headers
-    if (!track->event_format)
-        event_format_fallback(track);
-
-    ass_process_force_style(track);
-}
-
-static int check_duplicate_event(ASS_Track *track, int ReadOrder)
-{
-    int i;
-    for (i = 0; i < track->n_events - 1; ++i)   // ignoring last event, it is the one we are comparing with
-        if (track->events[i].ReadOrder == ReadOrder)
-            return 1;
-    return 0;
-}
-
-/**
- * \brief Process a chunk of subtitle stream data. In Matroska, this contains exactly 1 event (or a commentary).
- * \param track track
- * \param data string to parse
- * \param size length of data
- * \param timecode starting time of the event (milliseconds)
- * \param duration duration of the event (milliseconds)
-*/
-void ass_process_chunk(ASS_Track *track, char *data, int size,
-                       long long timecode, long long duration)
-{
-    char *str;
-    int eid;
-    char *p;
-    char *token;
-    ASS_Event *event;
-
-    if (!track->event_format) {
-        ass_msg(track->library, MSGL_WARN, "Event format header missing");
-        return;
-    }
-
-    str = malloc(size + 1);
-    memcpy(str, data, size);
-    str[size] = '\0';
-    ass_msg(track->library, MSGL_V, "Event at %" PRId64 ", +%" PRId64 ": %s",
-           (int64_t) timecode, (int64_t) duration, str);
-
-    eid = ass_alloc_event(track);
-    event = track->events + eid;
-
-    p = str;
-
-    do {
-        NEXT(p, token);
-        event->ReadOrder = atoi(token);
-        if (check_duplicate_event(track, event->ReadOrder))
-            break;
-
-        NEXT(p, token);
-        event->Layer = atoi(token);
-
-        process_event_tail(track, event, p, 3);
-
-        event->Start = timecode;
-        event->Duration = duration;
-
-        free(str);
-        return;
-//              dump_events(tid);
-    } while (0);
-    // some error
-    ass_free_event(track, eid);
-    track->n_events--;
-    free(str);
-}
-
-/**
- * \brief Flush buffered events.
- * \param track track
-*/
-void ass_flush_events(ASS_Track *track)
-{
-    if (track->events) {
-        int eid;
-        for (eid = 0; eid < track->n_events; eid++)
-            ass_free_event(track, eid);
-        track->n_events = 0;
-    }
-}
-
-#ifdef CONFIG_ICONV
-/** \brief recode buffer to utf-8
- * constraint: codepage != 0
- * \param data pointer to text buffer
- * \param size buffer size
- * \return a pointer to recoded buffer, caller is responsible for freeing it
-**/
-static char *sub_recode(ASS_Library *library, char *data, size_t size,
-                        char *codepage)
-{
-    iconv_t icdsc;
-    char *tocp = "UTF-8";
-    char *outbuf;
-    assert(codepage);
-
-    {
-        const char *cp_tmp = codepage;
-#ifdef CONFIG_ENCA
-        char enca_lang[3], enca_fallback[100];
-        if (sscanf(codepage, "enca:%2s:%99s", enca_lang, enca_fallback) == 2
-            || sscanf(codepage, "ENCA:%2s:%99s", enca_lang,
-                      enca_fallback) == 2) {
-            cp_tmp =
-                ass_guess_buffer_cp(library, (unsigned char *) data, size,
-                                    enca_lang, enca_fallback);
-        }
-#endif
-        if ((icdsc = iconv_open(tocp, cp_tmp)) != (iconv_t) (-1)) {
-            ass_msg(library, MSGL_V, "Opened iconv descriptor");
-        } else
-            ass_msg(library, MSGL_ERR, "Error opening iconv descriptor");
-    }
-
-    {
-        size_t osize = size;
-        size_t ileft = size;
-        size_t oleft = size - 1;
-        char *ip;
-        char *op;
-        size_t rc;
-        int clear = 0;
-
-        outbuf = malloc(osize);
-        ip = data;
-        op = outbuf;
-
-        while (1) {
-            if (ileft)
-                rc = iconv(icdsc, &ip, &ileft, &op, &oleft);
-            else {              // clear the conversion state and leave
-                clear = 1;
-                rc = iconv(icdsc, NULL, NULL, &op, &oleft);
-            }
-            if (rc == (size_t) (-1)) {
-                if (errno == E2BIG) {
-                    size_t offset = op - outbuf;
-                    outbuf = (char *) realloc(outbuf, osize + size);
-                    op = outbuf + offset;
-                    osize += size;
-                    oleft += size;
-                } else {
-                    ass_msg(library, MSGL_WARN, "Error recoding file");
-                    return NULL;
-                }
-            } else if (clear)
-                break;
-        }
-        outbuf[osize - oleft - 1] = 0;
-    }
-
-    if (icdsc != (iconv_t) (-1)) {
-        (void) iconv_close(icdsc);
-        icdsc = (iconv_t) (-1);
-        ass_msg(library, MSGL_V, "Closed iconv descriptor");
-    }
-
-    return outbuf;
-}
-#endif                          // ICONV
-
-/**
- * \brief read file contents into newly allocated buffer
- * \param fname file name
- * \param bufsize out: file size
- * \return pointer to file contents. Caller is responsible for its deallocation.
- */
-static char *read_file(ASS_Library *library, char *fname, size_t *bufsize)
-{
-    int res;
-    long sz;
-    long bytes_read;
-    char *buf;
-
-    FILE *fp = fopen(fname, "rb");
-    if (!fp) {
-        ass_msg(library, MSGL_WARN,
-                "ass_read_file(%s): fopen failed", fname);
-        return 0;
-    }
-    res = fseek(fp, 0, SEEK_END);
-    if (res == -1) {
-        ass_msg(library, MSGL_WARN,
-                "ass_read_file(%s): fseek failed", fname);
-        fclose(fp);
-        return 0;
-    }
-
-    sz = ftell(fp);
-    rewind(fp);
-
-    ass_msg(library, MSGL_V, "File size: %ld", sz);
-
-    buf = malloc(sz + 1);
-    assert(buf);
-    bytes_read = 0;
-    do {
-        res = fread(buf + bytes_read, 1, sz - bytes_read, fp);
-        if (res <= 0) {
-            ass_msg(library, MSGL_INFO, "Read failed, %d: %s", errno,
-                    strerror(errno));
-            fclose(fp);
-            free(buf);
-            return 0;
-        }
-        bytes_read += res;
-    } while (sz - bytes_read > 0);
-    buf[sz] = '\0';
-    fclose(fp);
-
-    if (bufsize)
-        *bufsize = sz;
-    return buf;
-}
-
-/*
- * \param buf pointer to subtitle text in utf-8
- */
-static ASS_Track *parse_memory(ASS_Library *library, char *buf)
-{
-    ASS_Track *track;
-    int i;
-
-    track = ass_new_track(library);
-
-    // process header
-    process_text(track, buf);
-
-    // external SSA/ASS subs does not have ReadOrder field
-    for (i = 0; i < track->n_events; ++i)
-        track->events[i].ReadOrder = i;
-
-    // there is no explicit end-of-font marker in ssa/ass
-    if (track->parser_priv->fontname)
-        decode_font(track);
-
-    if (track->track_type == TRACK_TYPE_UNKNOWN) {
-        ass_free_track(track);
-        return 0;
-    }
-
-    ass_process_force_style(track);
-
-    return track;
-}
-
-/**
- * \brief Read subtitles from memory.
- * \param library libass library object
- * \param buf pointer to subtitles text
- * \param bufsize size of buffer
- * \param codepage recode buffer contents from given codepage
- * \return newly allocated track
-*/
-ASS_Track *ass_read_memory(ASS_Library *library, char *buf,
-                           size_t bufsize, char *codepage)
-{
-    ASS_Track *track;
-    int need_free = 0;
-
-    if (!buf)
-        return 0;
-
-#ifdef CONFIG_ICONV
-    if (codepage) {
-        buf = sub_recode(library, buf, bufsize, codepage);
-        if (!buf)
-            return 0;
-        else
-            need_free = 1;
-    }
-#endif
-    track = parse_memory(library, buf);
-    if (need_free)
-        free(buf);
-    if (!track)
-        return 0;
-
-    ass_msg(library, MSGL_INFO, "Added subtitle file: "
-            "<memory> (%d styles, %d events)",
-            track->n_styles, track->n_events);
-    return track;
-}
-
-static char *read_file_recode(ASS_Library *library, char *fname,
-                              char *codepage, size_t *size)
-{
-    char *buf;
-    size_t bufsize;
-
-    buf = read_file(library, fname, &bufsize);
-    if (!buf)
-        return 0;
-#ifdef CONFIG_ICONV
-    if (codepage) {
-        char *tmpbuf = sub_recode(library, buf, bufsize, codepage);
-        free(buf);
-        buf = tmpbuf;
-    }
-    if (!buf)
-        return 0;
-#endif
-    *size = bufsize;
-    return buf;
-}
-
-/**
- * \brief Read subtitles from file.
- * \param library libass library object
- * \param fname file name
- * \param codepage recode buffer contents from given codepage
- * \return newly allocated track
-*/
-ASS_Track *ass_read_file(ASS_Library *library, char *fname,
-                         char *codepage)
-{
-    char *buf;
-    ASS_Track *track;
-    size_t bufsize;
-
-    buf = read_file_recode(library, fname, codepage, &bufsize);
-    if (!buf)
-        return 0;
-    track = parse_memory(library, buf);
-    free(buf);
-    if (!track)
-        return 0;
-
-    track->name = strdup(fname);
-
-    ass_msg(library, MSGL_INFO,
-            "Added subtitle file: '%s' (%d styles, %d events)",
-            fname, track->n_styles, track->n_events);
-
-    return track;
-}
-
-/**
- * \brief read styles from file into already initialized track
- */
-int ass_read_styles(ASS_Track *track, char *fname, char *codepage)
-{
-    char *buf;
-    ParserState old_state;
-    size_t sz;
-
-    buf = read_file(track->library, fname, &sz);
-    if (!buf)
-        return 1;
-#ifdef CONFIG_ICONV
-    if (codepage) {
-        char *tmpbuf;
-        tmpbuf = sub_recode(track->library, buf, sz, codepage);
-        free(buf);
-        buf = tmpbuf;
-    }
-    if (!buf)
-        return 0;
-#endif
-
-    old_state = track->parser_priv->state;
-    track->parser_priv->state = PST_STYLES;
-    process_text(track, buf);
-    track->parser_priv->state = old_state;
-
-    return 0;
-}
-
-long long ass_step_sub(ASS_Track *track, long long now, int movement)
-{
-    int i;
-
-    if (movement == 0)
-        return 0;
-    if (track->n_events == 0)
-        return 0;
-
-    if (movement < 0)
-        for (i = 0;
-             (i < track->n_events)
-             &&
-             ((long long) (track->events[i].Start +
-                           track->events[i].Duration) <= now); ++i) {
-    } else
-        for (i = track->n_events - 1;
-             (i >= 0) && ((long long) (track->events[i].Start) > now);
-             --i) {
-        }
-
-    // -1 and n_events are ok
-    assert(i >= -1);
-    assert(i <= track->n_events);
-    i += movement;
-    if (i < 0)
-        i = 0;
-    if (i >= track->n_events)
-        i = track->n_events - 1;
-    return ((long long) track->events[i].Start) - now;
-}
-
-ASS_Track *ass_new_track(ASS_Library *library)
-{
-    ASS_Track *track = calloc(1, sizeof(ASS_Track));
-    track->library = library;
-    track->ScaledBorderAndShadow = 1;
-    track->parser_priv = calloc(1, sizeof(ASS_ParserPriv));
-    return track;
-}
diff --git a/aegisub/libass/ass.h b/aegisub/libass/ass.h
deleted file mode 100644
index 3762bffe4..000000000
--- a/aegisub/libass/ass.h
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef LIBASS_ASS_H
-#define LIBASS_ASS_H
-
-#include <stdio.h>
-#include <stdarg.h>
-#include "ass_types.h"
-
-#define LIBASS_VERSION 0x00911000
-
-/*
- * A linked list of images produced by an ass renderer.
- *
- * These images have to be rendered in-order for the correct screen
- * composition.  The libass renderer clips these bitmaps to the frame size.
- * w/h can be zero, in this case the bitmap should not be rendered at all.
- * The last bitmap row is not guaranteed to be padded up to stride size,
- * e.g. in the worst case a bitmap has the size stride * (h - 1) + w.
- */
-typedef struct ass_image {
-    int w, h;                   // Bitmap width/height
-    int stride;                 // Bitmap stride
-    unsigned char *bitmap;      // 1bpp stride*h alpha buffer
-                                // Note: the last row may not be padded to
-                                // bitmap stride!
-    uint32_t color;             // Bitmap color and alpha, RGBA
-    int dst_x, dst_y;           // Bitmap placement inside the video frame
-
-    struct ass_image *next;   // Next image, or NULL
-} ASS_Image;
-
-/*
- * Hinting type. (see ass_set_hinting below)
- *
- * FreeType's native hinter is still buggy sometimes and it is recommended
- * to use the light autohinter, ASS_HINTING_LIGHT, instead.  For best
- * compatibility with problematic fonts, disable hinting.
- */
-typedef enum {
-    ASS_HINTING_NONE = 0,
-    ASS_HINTING_LIGHT,
-    ASS_HINTING_NORMAL,
-    ASS_HINTING_NATIVE
-} ASS_Hinting;
-
-/**
- * \brief Initialize the library.
- * \return library handle or NULL if failed
- */
-ASS_Library *ass_library_init(void);
-
-/**
- * \brief Finalize the library
- * \param priv library handle
- */
-void ass_library_done(ASS_Library *priv);
-
-/**
- * \brief Set additional fonts directory.
- * Optional directory that will be scanned for fonts recursively.  The fonts
- * found are used for font lookup.
- * NOTE: A valid font directory is not needed to support embedded fonts.
- *
- * \param priv library handle
- * \param fonts_dir directory with additional fonts
- */
-void ass_set_fonts_dir(ASS_Library *priv, const char *fonts_dir);
-
-/**
- * \brief Whether fonts should be extracted from track data.
- * \param priv library handle
- * \param extract whether to extract fonts
- */
-void ass_set_extract_fonts(ASS_Library *priv, int extract);
-
-/**
- * \brief Register style overrides with a library instance.
- * The overrides should have the form [Style.]Param=Value, e.g.
- *   SomeStyle.Font=Arial
- *   ScaledBorderAndShadow=yes
- *
- * \param priv library handle
- * \param list NULL-terminated list of strings
- */
-void ass_set_style_overrides(ASS_Library *priv, char **list);
-
-/**
- * \brief Explicitly process style overrides for a track.
- * \param track track handle
- */
-void ass_process_force_style(ASS_Track *track);
-
-/**
- * \brief Register a callback for debug/info messages.
- * If a callback is registered, it is called for every message emitted by
- * libass.  The callback receives a format string and a list of arguments,
- * to be used for the printf family of functions. Additionally, a log level
- * from 0 (FATAL errors) to 7 (verbose DEBUG) is passed.  Usually, level 5
- * should be used by applications.
- * If no callback is set, all messages level < 5 are printed to stderr,
- * prefixed with [ass].
- *
- * \param priv library handle
- * \param msg_cb pointer to callback function
- * \param data additional data, will be passed to callback
- */
-void ass_set_message_cb(ASS_Library *priv, void (*msg_cb)
-                        (int level, const char *fmt, va_list args, void *data),
-                        void *data);
-
-/**
- * \brief Initialize the renderer.
- * \param priv library handle
- * \return renderer handle or NULL if failed
- */
-ASS_Renderer *ass_renderer_init(ASS_Library *);
-
-/**
- * \brief Finalize the renderer.
- * \param priv renderer handle
- */
-void ass_renderer_done(ASS_Renderer *priv);
-
-/**
- * \brief Set the frame size in pixels, including margins.
- * \param priv renderer handle
- * \param w width
- * \param h height
- */
-void ass_set_frame_size(ASS_Renderer *priv, int w, int h);
-
-/**
- * \brief Set frame margins.  These values may be negative if pan-and-scan
- * is used.
- * \param priv renderer handle
- * \param t top margin
- * \param b bottom margin
- * \param l left margin
- * \param r right margin
- */
-void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r);
-
-/**
- * \brief Whether margins should be used for placing regular events.
- * \param priv renderer handle
- * \param use whether to use the margins
- */
-void ass_set_use_margins(ASS_Renderer *priv, int use);
-
-/**
- * \brief Set aspect ratio parameters.
- * \param priv renderer handle
- * \param dar display aspect ratio (DAR), prescaled for output PAR
- * \param sar storage aspect ratio (SAR)
- */
-void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar);
-
-/**
- * \brief Set a fixed font scaling factor.
- * \param priv renderer handle
- * \param font_scale scaling factor, default is 1.0
- */
-void ass_set_font_scale(ASS_Renderer *priv, double font_scale);
-
-/**
- * \brief Set font hinting method.
- * \param priv renderer handle
- * \param ht hinting method
- */
-void ass_set_hinting(ASS_Renderer *priv, ASS_Hinting ht);
-
-/**
- * \brief Set line spacing. Will not be scaled with frame size.
- * \param priv renderer handle
- * \param line_spacing line spacing in pixels
- */
-void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing);
-
-/**
- * \brief Set font lookup defaults.
- * \param default_font path to default font to use. Must be supplied if
- * fontconfig is disabled or unavailable.
- * \param default_family fallback font family for fontconfig, or NULL
- * \param fc whether to use fontconfig
- * \param config path to fontconfig configuration file, or NULL.  Only relevant
- * if fontconfig is used.
- * \param update whether fontconfig cache should be built/updated now.  Only
- * relevant if fontconfig is used.
- *
- * NOTE: font lookup must be configured before an ASS_Renderer can be used.
- */
-void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
-                   const char *default_family, int fc, const char *config,
-                   int update);
-
-/**
- * \brief Update/build font cache.  This needs to be called if it was
- * disabled when ass_set_fonts was set.
- *
- * \param priv renderer handle
- * \return success
- */
-int ass_fonts_update(ASS_Renderer *priv);
-
-/**
- * \brief Set hard cache limits.  Do not set, or set to zero, for reasonable
- * defaults.
- *
- * \param priv renderer handle
- * \param glyph_max maximum number of cached glyphs
- * \param bitmap_max_size maximum bitmap cache size (in MB)
- */
-void ass_set_cache_limits(ASS_Renderer *priv, int glyph_max,
-                          int bitmap_max_size);
-
-/**
- * \brief Render a frame, producing a list of ASS_Image.
- * \param priv renderer handle
- * \param track subtitle track
- * \param now video timestamp in milliseconds
- * \param detect_change will be set to 1 if a change occured compared
- * to the last invocation
- */
-ASS_Image *ass_render_frame(ASS_Renderer *priv, ASS_Track *track,
-                            long long now, int *detect_change);
-
-
-/*
- * The following functions operate on track objects and do not need
- * an ass_renderer
- */
-
-/**
- * \brief Allocate a new empty track object.
- * \param library handle
- * \return pointer to empty track
- */
-ASS_Track *ass_new_track(ASS_Library *);
-
-/**
- * \brief Deallocate track and all its child objects (styles and events).
- * \param track track to deallocate
- */
-void ass_free_track(ASS_Track *track);
-
-/**
- * \brief Allocate new style.
- * \param track track
- * \return newly allocated style id
- */
-int ass_alloc_style(ASS_Track *track);
-
-/**
- * \brief Allocate new event.
- * \param track track
- * \return newly allocated event id
- */
-int ass_alloc_event(ASS_Track *track);
-
-/**
- * \brief Delete a style.
- * \param track track
- * \param sid style id
- * Deallocates style data. Does not modify track->n_styles.
- */
-void ass_free_style(ASS_Track *track, int sid);
-
-/**
- * \brief Delete an event.
- * \param track track
- * \param eid event id
- * Deallocates event data. Does not modify track->n_events.
- */
-void ass_free_event(ASS_Track *track, int eid);
-
-/**
- * \brief Parse a chunk of subtitle stream data.
- * \param track track
- * \param data string to parse
- * \param size length of data
- */
-void ass_process_data(ASS_Track *track, char *data, int size);
-
-/**
- * \brief Parse Codec Private section of the subtitle stream, in Matroska
- * format.  See the Matroska specification for details.
- * \param track target track
- * \param data string to parse
- * \param size length of data
- */
-void ass_process_codec_private(ASS_Track *track, char *data, int size);
-
-/**
- * \brief Parse a chunk of subtitle stream data. A chunk contains exactly one
- * event in Matroska format.  See the Matroska specification for details.
- * \param track track
- * \param data string to parse
- * \param size length of data
- * \param timecode starting time of the event (milliseconds)
- * \param duration duration of the event (milliseconds)
- */
-void ass_process_chunk(ASS_Track *track, char *data, int size,
-                       long long timecode, long long duration);
-
-/**
- * \brief Flush buffered events.
- * \param track track
-*/
-void ass_flush_events(ASS_Track *track);
-
-/**
- * \brief Read subtitles from file.
- * \param library library handle
- * \param fname file name
- * \param codepage encoding (iconv format)
- * \return newly allocated track
-*/
-ASS_Track *ass_read_file(ASS_Library *library, char *fname,
-                         char *codepage);
-
-/**
- * \brief Read subtitles from memory.
- * \param library library handle
- * \param buf pointer to subtitles text
- * \param bufsize size of buffer
- * \param codepage encoding (iconv format)
- * \return newly allocated track
-*/
-ASS_Track *ass_read_memory(ASS_Library *library, char *buf,
-                           size_t bufsize, char *codepage);
-/**
- * \brief Read styles from file into already initialized track.
- * \param fname file name
- * \param codepage encoding (iconv format)
- * \return 0 on success
- */
-int ass_read_styles(ASS_Track *track, char *fname, char *codepage);
-
-/**
- * \brief Add a memory font.
- * \param library library handle
- * \param name attachment name
- * \param data binary font data
- * \param data_size data size
-*/
-void ass_add_font(ASS_Library *library, char *name, char *data,
-                  int data_size);
-
-/**
- * \brief Remove all fonts stored in an ass_library object.
- * \param library library handle
- */
-void ass_clear_fonts(ASS_Library *library);
-
-/**
- * \brief Calculates timeshift from now to the start of some other subtitle
- * event, depending on movement parameter.
- * \param track subtitle track
- * \param now current time in milliseconds
- * \param movement how many events to skip from the one currently displayed
- * +2 means "the one after the next", -1 means "previous"
- * \return timeshift in milliseconds
- */
-long long ass_step_sub(ASS_Track *track, long long now, int movement);
-
-#endif /* LIBASS_ASS_H */
diff --git a/aegisub/libass/ass_bitmap.c b/aegisub/libass/ass_bitmap.c
deleted file mode 100644
index 4865974cd..000000000
--- a/aegisub/libass/ass_bitmap.c
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-#include <ft2build.h>
-#include FT_GLYPH_H
-
-#include "ass_utils.h"
-#include "ass_bitmap.h"
-
-struct ass_synth_priv {
-    int tmp_w, tmp_h;
-    unsigned short *tmp;
-
-    int g_r;
-    int g_w;
-
-    unsigned *g;
-    unsigned *gt2;
-
-    double radius;
-};
-
-static const unsigned int maxcolor = 255;
-static const unsigned base = 256;
-
-static int generate_tables(ASS_SynthPriv *priv, double radius)
-{
-    double A = log(1.0 / base) / (radius * radius * 2);
-    int mx, i;
-    double volume_diff, volume_factor = 0;
-    unsigned volume;
-
-    if (priv->radius == radius)
-        return 0;
-    else
-        priv->radius = radius;
-
-    priv->g_r = ceil(radius);
-    priv->g_w = 2 * priv->g_r + 1;
-
-    if (priv->g_r) {
-        priv->g = realloc(priv->g, priv->g_w * sizeof(unsigned));
-        priv->gt2 = realloc(priv->gt2, 256 * priv->g_w * sizeof(unsigned));
-        if (priv->g == NULL || priv->gt2 == NULL) {
-            return -1;
-        }
-    }
-
-    if (priv->g_r) {
-        // gaussian curve with volume = 256
-        for (volume_diff = 10000000; volume_diff > 0.0000001;
-             volume_diff *= 0.5) {
-            volume_factor += volume_diff;
-            volume = 0;
-            for (i = 0; i < priv->g_w; ++i) {
-                priv->g[i] =
-                    (unsigned) (exp(A * (i - priv->g_r) * (i - priv->g_r)) *
-                                volume_factor + .5);
-                volume += priv->g[i];
-            }
-            if (volume > 256)
-                volume_factor -= volume_diff;
-        }
-        volume = 0;
-        for (i = 0; i < priv->g_w; ++i) {
-            priv->g[i] =
-                (unsigned) (exp(A * (i - priv->g_r) * (i - priv->g_r)) *
-                            volume_factor + .5);
-            volume += priv->g[i];
-        }
-
-        // gauss table:
-        for (mx = 0; mx < priv->g_w; mx++) {
-            for (i = 0; i < 256; i++) {
-                priv->gt2[mx + i * priv->g_w] = i * priv->g[mx];
-            }
-        }
-    }
-
-    return 0;
-}
-
-static void resize_tmp(ASS_SynthPriv *priv, int w, int h)
-{
-    if (priv->tmp_w >= w && priv->tmp_h >= h)
-        return;
-    if (priv->tmp_w == 0)
-        priv->tmp_w = 64;
-    if (priv->tmp_h == 0)
-        priv->tmp_h = 64;
-    while (priv->tmp_w < w)
-        priv->tmp_w *= 2;
-    while (priv->tmp_h < h)
-        priv->tmp_h *= 2;
-    free(priv->tmp);
-    priv->tmp = malloc((priv->tmp_w + 1) * priv->tmp_h * sizeof(short));
-}
-
-ASS_SynthPriv *ass_synth_init(double radius)
-{
-    ASS_SynthPriv *priv = calloc(1, sizeof(ASS_SynthPriv));
-    generate_tables(priv, radius);
-    return priv;
-}
-
-void ass_synth_done(ASS_SynthPriv *priv)
-{
-    free(priv->tmp);
-    free(priv->g);
-    free(priv->gt2);
-    free(priv);
-}
-
-static Bitmap *alloc_bitmap(int w, int h)
-{
-    Bitmap *bm;
-    bm = malloc(sizeof(Bitmap));
-    bm->buffer = calloc(w, h);
-    bm->w = w;
-    bm->h = h;
-    bm->left = bm->top = 0;
-    return bm;
-}
-
-void ass_free_bitmap(Bitmap *bm)
-{
-    if (bm)
-        free(bm->buffer);
-    free(bm);
-}
-
-static Bitmap *copy_bitmap(const Bitmap *src)
-{
-    Bitmap *dst = alloc_bitmap(src->w, src->h);
-    dst->left = src->left;
-    dst->top = src->top;
-    memcpy(dst->buffer, src->buffer, src->w * src->h);
-    return dst;
-}
-
-int check_glyph_area(ASS_Library *library, FT_Glyph glyph)
-{
-    FT_BBox bbox;
-    long long dx, dy;
-    FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox);
-    dx = bbox.xMax - bbox.xMin;
-    dy = bbox.yMax - bbox.yMin;
-    if (dx * dy > 8000000) {
-        ass_msg(library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx",
-               (int) dx, (int) dy);
-        return 1;
-    } else
-        return 0;
-}
-
-static Bitmap *glyph_to_bitmap_internal(ASS_Library *library,
-                                          FT_Glyph glyph, int bord)
-{
-    FT_BitmapGlyph bg;
-    FT_Bitmap *bit;
-    Bitmap *bm;
-    int w, h;
-    unsigned char *src;
-    unsigned char *dst;
-    int i;
-    int error;
-
-    if (check_glyph_area(library, glyph))
-        return 0;
-    error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
-    if (error) {
-        ass_msg(library, MSGL_WARN, "FT_Glyph_To_Bitmap error %d",
-               error);
-        return 0;
-    }
-
-    bg = (FT_BitmapGlyph) glyph;
-    bit = &(bg->bitmap);
-    if (bit->pixel_mode != FT_PIXEL_MODE_GRAY) {
-        ass_msg(library, MSGL_WARN, "Unsupported pixel mode: %d",
-               (int) (bit->pixel_mode));
-        FT_Done_Glyph(glyph);
-        return 0;
-    }
-
-    w = bit->width;
-    h = bit->rows;
-    bm = alloc_bitmap(w + 2 * bord, h + 2 * bord);
-    bm->left = bg->left - bord;
-    bm->top = -bg->top - bord;
-
-    src = bit->buffer;
-    dst = bm->buffer + bord + bm->w * bord;
-    for (i = 0; i < h; ++i) {
-        memcpy(dst, src, w);
-        src += bit->pitch;
-        dst += bm->w;
-    }
-
-    FT_Done_Glyph(glyph);
-    return bm;
-}
-
-/**
- * \brief fix outline bitmap
- *
- * The glyph bitmap is subtracted from outline bitmap. This way looks much
- * better in some cases.
- */
-static void fix_outline(Bitmap *bm_g, Bitmap *bm_o)
-{
-    int x, y;
-    const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left;
-    const int t = bm_o->top > bm_g->top ? bm_o->top : bm_g->top;
-    const int r =
-        bm_o->left + bm_o->w <
-        bm_g->left + bm_g->w ? bm_o->left + bm_o->w : bm_g->left + bm_g->w;
-    const int b =
-        bm_o->top + bm_o->h <
-        bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h;
-
-    unsigned char *g =
-        bm_g->buffer + (t - bm_g->top) * bm_g->w + (l - bm_g->left);
-    unsigned char *o =
-        bm_o->buffer + (t - bm_o->top) * bm_o->w + (l - bm_o->left);
-
-    for (y = 0; y < b - t; ++y) {
-        for (x = 0; x < r - l; ++x) {
-            unsigned char c_g, c_o;
-            c_g = g[x];
-            c_o = o[x];
-            o[x] = (c_o > c_g) ? c_o - (c_g / 2) : 0;
-        }
-        g += bm_g->w;
-        o += bm_o->w;
-    }
-}
-
-/**
- * \brief Shift a bitmap by the fraction of a pixel in x and y direction
- * expressed in 26.6 fixed point
- */
-static void shift_bitmap(unsigned char *buf, int w, int h, int shift_x,
-                         int shift_y)
-{
-    int x, y, b;
-
-    // Shift in x direction
-    if (shift_x > 0) {
-        for (y = 0; y < h; y++) {
-            for (x = w - 1; x > 0; x--) {
-                b = (buf[x + y * w - 1] * shift_x) >> 6;
-                buf[x + y * w - 1] -= b;
-                buf[x + y * w] += b;
-            }
-        }
-    } else if (shift_x < 0) {
-        shift_x = -shift_x;
-        for (y = 0; y < h; y++) {
-            for (x = 0; x < w - 1; x++) {
-                b = (buf[x + y * w + 1] * shift_x) >> 6;
-                buf[x + y * w + 1] -= b;
-                buf[x + y * w] += b;
-            }
-        }
-    }
-
-    // Shift in y direction
-    if (shift_y > 0) {
-        for (x = 0; x < w; x++) {
-            for (y = h - 1; y > 0; y--) {
-                b = (buf[x + (y - 1) * w] * shift_y) >> 6;
-                buf[x + (y - 1) * w] -= b;
-                buf[x + y * w] += b;
-            }
-        }
-    } else if (shift_y < 0) {
-        shift_y = -shift_y;
-        for (x = 0; x < w; x++) {
-            for (y = 0; y < h - 1; y++) {
-                b = (buf[x + (y + 1) * w] * shift_y) >> 6;
-                buf[x + (y + 1) * w] -= b;
-                buf[x + y * w] += b;
-            }
-        }
-    }
-}
-
-/*
- * Gaussian blur.  An fast pure C implementation from MPlayer.
- */
-static void ass_gauss_blur(unsigned char *buffer, unsigned short *tmp2,
-                           int width, int height, int stride, int *m2,
-                           int r, int mwidth)
-{
-
-    int x, y;
-
-    unsigned char *s = buffer;
-    unsigned short *t = tmp2 + 1;
-    for (y = 0; y < height; y++) {
-        memset(t - 1, 0, (width + 1) * sizeof(short));
-
-        for (x = 0; x < r; x++) {
-            const int src = s[x];
-            if (src) {
-                register unsigned short *dstp = t + x - r;
-                int mx;
-                unsigned *m3 = (unsigned *) (m2 + src * mwidth);
-                for (mx = r - x; mx < mwidth; mx++) {
-                    dstp[mx] += m3[mx];
-                }
-            }
-        }
-
-        for (; x < width - r; x++) {
-            const int src = s[x];
-            if (src) {
-                register unsigned short *dstp = t + x - r;
-                int mx;
-                unsigned *m3 = (unsigned *) (m2 + src * mwidth);
-                for (mx = 0; mx < mwidth; mx++) {
-                    dstp[mx] += m3[mx];
-                }
-            }
-        }
-
-        for (; x < width; x++) {
-            const int src = s[x];
-            if (src) {
-                register unsigned short *dstp = t + x - r;
-                int mx;
-                const int x2 = r + width - x;
-                unsigned *m3 = (unsigned *) (m2 + src * mwidth);
-                for (mx = 0; mx < x2; mx++) {
-                    dstp[mx] += m3[mx];
-                }
-            }
-        }
-
-        s += stride;
-        t += width + 1;
-    }
-
-    t = tmp2;
-    for (x = 0; x < width; x++) {
-        for (y = 0; y < r; y++) {
-            unsigned short *srcp = t + y * (width + 1) + 1;
-            int src = *srcp;
-            if (src) {
-                register unsigned short *dstp = srcp - 1 + width + 1;
-                const int src2 = (src + 128) >> 8;
-                unsigned *m3 = (unsigned *) (m2 + src2 * mwidth);
-
-                int mx;
-                *srcp = 128;
-                for (mx = r - 1; mx < mwidth; mx++) {
-                    *dstp += m3[mx];
-                    dstp += width + 1;
-                }
-            }
-        }
-        for (; y < height - r; y++) {
-            unsigned short *srcp = t + y * (width + 1) + 1;
-            int src = *srcp;
-            if (src) {
-                register unsigned short *dstp = srcp - 1 - r * (width + 1);
-                const int src2 = (src + 128) >> 8;
-                unsigned *m3 = (unsigned *) (m2 + src2 * mwidth);
-
-                int mx;
-                *srcp = 128;
-                for (mx = 0; mx < mwidth; mx++) {
-                    *dstp += m3[mx];
-                    dstp += width + 1;
-                }
-            }
-        }
-        for (; y < height; y++) {
-            unsigned short *srcp = t + y * (width + 1) + 1;
-            int src = *srcp;
-            if (src) {
-                const int y2 = r + height - y;
-                register unsigned short *dstp = srcp - 1 - r * (width + 1);
-                const int src2 = (src + 128) >> 8;
-                unsigned *m3 = (unsigned *) (m2 + src2 * mwidth);
-
-                int mx;
-                *srcp = 128;
-                for (mx = 0; mx < y2; mx++) {
-                    *dstp += m3[mx];
-                    dstp += width + 1;
-                }
-            }
-        }
-        t++;
-    }
-
-    t = tmp2;
-    s = buffer;
-    for (y = 0; y < height; y++) {
-        for (x = 0; x < width; x++) {
-            s[x] = t[x] >> 8;
-        }
-        s += stride;
-        t += width + 1;
-    }
-}
-
-/**
- * \brief Blur with [[1,2,1]. [2,4,2], [1,2,1]] kernel
- * This blur is the same as the one employed by vsfilter.
- */
-static void be_blur(unsigned char *buf, int w, int h)
-{
-    unsigned int x, y;
-    unsigned int old_sum, new_sum;
-
-    for (y = 0; y < h; y++) {
-        old_sum = 2 * buf[y * w];
-        for (x = 0; x < w - 1; x++) {
-            new_sum = buf[y * w + x] + buf[y * w + x + 1];
-            buf[y * w + x] = (old_sum + new_sum) >> 2;
-            old_sum = new_sum;
-        }
-    }
-
-    for (x = 0; x < w; x++) {
-        old_sum = 2 * buf[x];
-        for (y = 0; y < h - 1; y++) {
-            new_sum = buf[y * w + x] + buf[(y + 1) * w + x];
-            buf[y * w + x] = (old_sum + new_sum) >> 2;
-            old_sum = new_sum;
-        }
-    }
-}
-
-int glyph_to_bitmap(ASS_Library *library, ASS_SynthPriv *priv_blur,
-                    FT_Glyph glyph, FT_Glyph outline_glyph,
-                    Bitmap **bm_g, Bitmap **bm_o, Bitmap **bm_s,
-                    int be, double blur_radius, FT_Vector shadow_offset,
-                    int border_style)
-{
-    int bbord;
-    int gbord;
-    int bord;
-    blur_radius *= 2;
-    bbord = be > 0 ? sqrt(2 * be) : 0;
-    gbord = blur_radius > 0.0 ? blur_radius + 1 : 0;
-    bord = FFMAX(bbord, gbord);
-    if (bord == 0 && (shadow_offset.x || shadow_offset.y))
-        bord = 1;
-
-    assert(bm_g && bm_o && bm_s);
-
-    *bm_g = *bm_o = *bm_s = 0;
-
-    if (glyph)
-        *bm_g = glyph_to_bitmap_internal(library, glyph, bord);
-    if (!*bm_g)
-        return 1;
-
-    if (outline_glyph) {
-        *bm_o = glyph_to_bitmap_internal(library, outline_glyph, bord);
-        if (!*bm_o) {
-            return 1;
-        }
-    }
-
-    // Apply box blur (multiple passes, if requested)
-    while (be--) {
-        if (*bm_o)
-            be_blur((*bm_o)->buffer, (*bm_o)->w, (*bm_o)->h);
-        else
-            be_blur((*bm_g)->buffer, (*bm_g)->w, (*bm_g)->h);
-    }
-
-    // Apply gaussian blur
-    if (blur_radius > 0.0) {
-        if (*bm_o)
-            resize_tmp(priv_blur, (*bm_o)->w, (*bm_o)->h);
-        else
-            resize_tmp(priv_blur, (*bm_g)->w, (*bm_g)->h);
-        generate_tables(priv_blur, blur_radius);
-        if (*bm_o)
-            ass_gauss_blur((*bm_o)->buffer, priv_blur->tmp,
-                           (*bm_o)->w, (*bm_o)->h, (*bm_o)->w,
-                           (int *) priv_blur->gt2, priv_blur->g_r,
-                           priv_blur->g_w);
-        else
-            ass_gauss_blur((*bm_g)->buffer, priv_blur->tmp,
-                           (*bm_g)->w, (*bm_g)->h, (*bm_g)->w,
-                           (int *) priv_blur->gt2, priv_blur->g_r,
-                           priv_blur->g_w);
-    }
-
-    // Create shadow and fix outline as needed
-    if (*bm_o && border_style != 3) {
-        *bm_s = copy_bitmap(*bm_o);
-        fix_outline(*bm_g, *bm_o);
-    } else if (*bm_o) {
-        *bm_s = copy_bitmap(*bm_o);
-    } else
-        *bm_s = copy_bitmap(*bm_g);
-
-    assert(bm_s);
-
-    shift_bitmap((*bm_s)->buffer, (*bm_s)->w,(*bm_s)->h,
-                 shadow_offset.x, shadow_offset.y);
-
-    return 0;
-}
diff --git a/aegisub/libass/ass_bitmap.h b/aegisub/libass/ass_bitmap.h
deleted file mode 100644
index 287b63828..000000000
--- a/aegisub/libass/ass_bitmap.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef LIBASS_BITMAP_H
-#define LIBASS_BITMAP_H
-
-#include <ft2build.h>
-#include FT_GLYPH_H
-
-#include "ass.h"
-
-typedef struct ass_synth_priv ASS_SynthPriv;
-
-ASS_SynthPriv *ass_synth_init(double);
-void ass_synth_done(ASS_SynthPriv *priv);
-
-typedef struct {
-    int left, top;
-    int w, h;                   // width, height
-    unsigned char *buffer;      // w x h buffer
-} Bitmap;
-
-/**
- * \brief perform glyph rendering
- * \param glyph original glyph
- * \param outline_glyph "border" glyph, produced from original by FreeType's glyph stroker
- * \param bm_g out: pointer to the bitmap of original glyph is returned here
- * \param bm_o out: pointer to the bitmap of outline (border) glyph is returned here
- * \param bm_g out: pointer to the bitmap of glyph shadow is returned here
- * \param be 1 = produces blurred bitmaps, 0 = normal bitmaps
- */
-int glyph_to_bitmap(ASS_Library *library, ASS_SynthPriv *priv_blur,
-                    FT_Glyph glyph, FT_Glyph outline_glyph,
-                    Bitmap **bm_g, Bitmap **bm_o, Bitmap **bm_s,
-                    int be, double blur_radius, FT_Vector shadow_offset,
-                    int border_style);
-
-void ass_free_bitmap(Bitmap *bm);
-int check_glyph_area(ASS_Library *library, FT_Glyph glyph);
-
-#endif                          /* LIBASS_BITMAP_H */
diff --git a/aegisub/libass/ass_cache.c b/aegisub/libass/ass_cache.c
deleted file mode 100644
index 46c2478f8..000000000
--- a/aegisub/libass/ass_cache.c
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include <inttypes.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_GLYPH_H
-
-#include <assert.h>
-
-#include "ass_utils.h"
-#include "ass.h"
-#include "ass_fontconfig.h"
-#include "ass_font.h"
-#include "ass_bitmap.h"
-#include "ass_cache.h"
-
-static unsigned hashmap_hash(void *buf, size_t len)
-{
-    return fnv_32a_buf(buf, len, FNV1_32A_INIT);
-}
-
-static int hashmap_key_compare(void *a, void *b, size_t size)
-{
-    return memcmp(a, b, size) == 0;
-}
-
-static void hashmap_item_dtor(void *key, size_t key_size, void *value,
-                              size_t value_size)
-{
-    free(key);
-    free(value);
-}
-
-Hashmap *hashmap_init(ASS_Library *library, size_t key_size,
-                      size_t value_size, int nbuckets,
-                      HashmapItemDtor item_dtor,
-                      HashmapKeyCompare key_compare,
-                      HashmapHash hash)
-{
-    Hashmap *map = calloc(1, sizeof(Hashmap));
-    map->library = library;
-    map->nbuckets = nbuckets;
-    map->key_size = key_size;
-    map->value_size = value_size;
-    map->root = calloc(nbuckets, sizeof(hashmap_item_p));
-    map->item_dtor = item_dtor ? item_dtor : hashmap_item_dtor;
-    map->key_compare = key_compare ? key_compare : hashmap_key_compare;
-    map->hash = hash ? hash : hashmap_hash;
-    return map;
-}
-
-void hashmap_done(Hashmap *map)
-{
-    int i;
-    // print stats
-    if (map->count > 0 || map->hit_count + map->miss_count > 0)
-        ass_msg(map->library, MSGL_V,
-               "cache statistics: \n  total accesses: %d\n  hits: %d\n  "
-               "misses: %d\n  object count: %d",
-               map->hit_count + map->miss_count, map->hit_count,
-               map->miss_count, map->count);
-
-    for (i = 0; i < map->nbuckets; ++i) {
-        HashmapItem *item = map->root[i];
-        while (item) {
-            HashmapItem *next = item->next;
-            map->item_dtor(item->key, map->key_size, item->value,
-                           map->value_size);
-            free(item);
-            item = next;
-        }
-    }
-    free(map->root);
-    free(map);
-}
-
-// does nothing if key already exists
-void *hashmap_insert(Hashmap *map, void *key, void *value)
-{
-    unsigned hash = map->hash(key, map->key_size);
-    HashmapItem **next = map->root + (hash % map->nbuckets);
-    while (*next) {
-        if (map->key_compare(key, (*next)->key, map->key_size))
-            return (*next)->value;
-        next = &((*next)->next);
-        assert(next);
-    }
-    (*next) = malloc(sizeof(HashmapItem));
-    (*next)->key = malloc(map->key_size);
-    (*next)->value = malloc(map->value_size);
-    memcpy((*next)->key, key, map->key_size);
-    memcpy((*next)->value, value, map->value_size);
-    (*next)->next = 0;
-
-    map->count++;
-    return (*next)->value;
-}
-
-void *hashmap_find(Hashmap *map, void *key)
-{
-    unsigned hash = map->hash(key, map->key_size);
-    HashmapItem *item = map->root[hash % map->nbuckets];
-    while (item) {
-        if (map->key_compare(key, item->key, map->key_size)) {
-            map->hit_count++;
-            return item->value;
-        }
-        item = item->next;
-    }
-    map->miss_count++;
-    return 0;
-}
-
-//---------------------------------
-// font cache
-
-static unsigned font_desc_hash(void *buf, size_t len)
-{
-    ASS_FontDesc *desc = buf;
-    unsigned hval;
-    hval = fnv_32a_str(desc->family, FNV1_32A_INIT);
-    hval = fnv_32a_buf(&desc->bold, sizeof(desc->bold), hval);
-    hval = fnv_32a_buf(&desc->italic, sizeof(desc->italic), hval);
-    return hval;
-}
-
-static int font_compare(void *key1, void *key2, size_t key_size)
-{
-    ASS_FontDesc *a = key1;
-    ASS_FontDesc *b = key2;
-    if (strcmp(a->family, b->family) != 0)
-        return 0;
-    if (a->bold != b->bold)
-        return 0;
-    if (a->italic != b->italic)
-        return 0;
-    if (a->treat_family_as_pattern != b->treat_family_as_pattern)
-        return 0;
-    if (a->vertical != b->vertical)
-        return 0;
-    return 1;
-}
-
-static void font_hash_dtor(void *key, size_t key_size, void *value,
-                           size_t value_size)
-{
-    ass_font_free(value);
-    free(key);
-}
-
-ASS_Font *ass_font_cache_find(Hashmap *font_cache,
-                              ASS_FontDesc *desc)
-{
-    return hashmap_find(font_cache, desc);
-}
-
-/**
- * \brief Add a face struct to cache.
- * \param font font struct
-*/
-void *ass_font_cache_add(Hashmap *font_cache, ASS_Font *font)
-{
-    return hashmap_insert(font_cache, &(font->desc), font);
-}
-
-Hashmap *ass_font_cache_init(ASS_Library *library)
-{
-    Hashmap *font_cache;
-    font_cache = hashmap_init(library, sizeof(ASS_FontDesc),
-                              sizeof(ASS_Font),
-                              1000,
-                              font_hash_dtor, font_compare, font_desc_hash);
-    return font_cache;
-}
-
-void ass_font_cache_done(Hashmap *font_cache)
-{
-    hashmap_done(font_cache);
-}
-
-
-// Create hash/compare functions for bitmap and glyph
-#define CREATE_HASH_FUNCTIONS
-#include "ass_cache_template.h"
-#define CREATE_COMPARISON_FUNCTIONS
-#include "ass_cache_template.h"
-
-//---------------------------------
-// bitmap cache
-
-static void bitmap_hash_dtor(void *key, size_t key_size, void *value,
-                             size_t value_size)
-{
-    BitmapHashValue *v = value;
-    if (v->bm)
-        ass_free_bitmap(v->bm);
-    if (v->bm_o)
-        ass_free_bitmap(v->bm_o);
-    if (v->bm_s)
-        ass_free_bitmap(v->bm_s);
-    free(key);
-    free(value);
-}
-
-void *cache_add_bitmap(Hashmap *bitmap_cache, BitmapHashKey *key,
-                       BitmapHashValue *val)
-{
-    // Note: this is only an approximation
-    if (val->bm_o)
-        bitmap_cache->cache_size += val->bm_o->w * val->bm_o->h * 3;
-    else if (val->bm)
-        bitmap_cache->cache_size += val->bm->w * val->bm->h * 3;
-
-    return hashmap_insert(bitmap_cache, key, val);
-}
-
-/**
- * \brief Get a bitmap from bitmap cache.
- * \param key hash key
- * \return requested hash val or 0 if not found
-*/
-BitmapHashValue *cache_find_bitmap(Hashmap *bitmap_cache,
-                                   BitmapHashKey *key)
-{
-    return hashmap_find(bitmap_cache, key);
-}
-
-Hashmap *ass_bitmap_cache_init(ASS_Library *library)
-{
-    Hashmap *bitmap_cache;
-    bitmap_cache = hashmap_init(library,
-                                sizeof(BitmapHashKey),
-                                sizeof(BitmapHashValue),
-                                0xFFFF + 13,
-                                bitmap_hash_dtor, bitmap_compare,
-                                bitmap_hash);
-    return bitmap_cache;
-}
-
-void ass_bitmap_cache_done(Hashmap *bitmap_cache)
-{
-    hashmap_done(bitmap_cache);
-}
-
-Hashmap *ass_bitmap_cache_reset(Hashmap *bitmap_cache)
-{
-    ASS_Library *lib = bitmap_cache->library;
-
-    ass_bitmap_cache_done(bitmap_cache);
-    return ass_bitmap_cache_init(lib);
-}
-
-//---------------------------------
-// glyph cache
-
-static void glyph_hash_dtor(void *key, size_t key_size, void *value,
-                            size_t value_size)
-{
-    GlyphHashValue *v = value;
-    if (v->glyph)
-        FT_Done_Glyph(v->glyph);
-    if (v->outline_glyph)
-        FT_Done_Glyph(v->outline_glyph);
-    free(key);
-    free(value);
-}
-
-void *cache_add_glyph(Hashmap *glyph_cache, GlyphHashKey *key,
-                      GlyphHashValue *val)
-{
-	if (val->glyph && val->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
-		FT_Bitmap *bitmap = &((FT_BitmapGlyph) val->glyph)->bitmap;
-		glyph_cache->cache_size += bitmap->rows * bitmap->pitch;
-	}
-
-    return hashmap_insert(glyph_cache, key, val);
-}
-
-/**
- * \brief Get a glyph from glyph cache.
- * \param key hash key
- * \return requested hash val or 0 if not found
-*/
-GlyphHashValue *cache_find_glyph(Hashmap *glyph_cache,
-                                 GlyphHashKey *key)
-{
-    return hashmap_find(glyph_cache, key);
-}
-
-Hashmap *ass_glyph_cache_init(ASS_Library *library)
-{
-    Hashmap *glyph_cache;
-    glyph_cache = hashmap_init(library, sizeof(GlyphHashKey),
-                               sizeof(GlyphHashValue),
-                               0xFFFF + 13,
-                               glyph_hash_dtor, glyph_compare, glyph_hash);
-    return glyph_cache;
-}
-
-void ass_glyph_cache_done(Hashmap *glyph_cache)
-{
-    hashmap_done(glyph_cache);
-}
-
-Hashmap *ass_glyph_cache_reset(Hashmap *glyph_cache)
-{
-    ASS_Library *lib = glyph_cache->library;
-
-    ass_glyph_cache_done(glyph_cache);
-    return ass_glyph_cache_init(lib);
-}
-
-
-//---------------------------------
-// composite cache
-
-static void composite_hash_dtor(void *key, size_t key_size, void *value,
-                                size_t value_size)
-{
-    CompositeHashValue *v = value;
-    free(v->a);
-    free(v->b);
-    free(key);
-    free(value);
-}
-
-void *cache_add_composite(Hashmap *composite_cache,
-                          CompositeHashKey *key,
-                          CompositeHashValue *val)
-{
-    return hashmap_insert(composite_cache, key, val);
-}
-
-/**
- * \brief Get a composite bitmap from composite cache.
- * \param key hash key
- * \return requested hash val or 0 if not found
-*/
-CompositeHashValue *cache_find_composite(Hashmap *composite_cache,
-                                         CompositeHashKey *key)
-{
-    return hashmap_find(composite_cache, key);
-}
-
-Hashmap *ass_composite_cache_init(ASS_Library *library)
-{
-    Hashmap *composite_cache;
-    composite_cache = hashmap_init(library, sizeof(CompositeHashKey),
-                                   sizeof(CompositeHashValue),
-                                   0xFFFF + 13,
-                                   composite_hash_dtor, composite_compare,
-                                   composite_hash);
-    return composite_cache;
-}
-
-void ass_composite_cache_done(Hashmap *composite_cache)
-{
-    hashmap_done(composite_cache);
-}
-
-Hashmap *ass_composite_cache_reset(Hashmap *composite_cache)
-{
-    ASS_Library *lib = composite_cache->library;
-
-    ass_composite_cache_done(composite_cache);
-    return ass_composite_cache_init(lib);
-}
diff --git a/aegisub/libass/ass_cache.h b/aegisub/libass/ass_cache.h
deleted file mode 100644
index 472bf359b..000000000
--- a/aegisub/libass/ass_cache.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef LIBASS_CACHE_H
-#define LIBASS_CACHE_H
-
-#include "ass.h"
-#include "ass_font.h"
-#include "ass_bitmap.h"
-
-typedef void (*HashmapItemDtor) (void *key, size_t key_size,
-                                 void *value, size_t value_size);
-typedef int (*HashmapKeyCompare) (void *key1, void *key2,
-                                  size_t key_size);
-typedef unsigned (*HashmapHash) (void *key, size_t key_size);
-
-typedef struct hashmap_item {
-    void *key;
-    void *value;
-    struct hashmap_item *next;
-} HashmapItem;
-typedef HashmapItem *hashmap_item_p;
-
-typedef struct {
-    int nbuckets;
-    size_t key_size, value_size;
-    hashmap_item_p *root;
-    HashmapItemDtor item_dtor;      // a destructor for hashmap key/value pairs
-    HashmapKeyCompare key_compare;
-    HashmapHash hash;
-    size_t cache_size;
-    // stats
-    int hit_count;
-    int miss_count;
-    int count;
-    ASS_Library *library;
-} Hashmap;
-
-Hashmap *hashmap_init(ASS_Library *library, size_t key_size,
-                      size_t value_size, int nbuckets,
-                      HashmapItemDtor item_dtor,
-                      HashmapKeyCompare key_compare,
-                      HashmapHash hash);
-void hashmap_done(Hashmap *map);
-void *hashmap_insert(Hashmap *map, void *key, void *value);
-void *hashmap_find(Hashmap *map, void *key);
-
-Hashmap *ass_font_cache_init(ASS_Library *library);
-ASS_Font *ass_font_cache_find(Hashmap *, ASS_FontDesc *desc);
-void *ass_font_cache_add(Hashmap *, ASS_Font *font);
-void ass_font_cache_done(Hashmap *);
-
-// Create definitions for bitmap_hash_key and glyph_hash_key
-#define CREATE_STRUCT_DEFINITIONS
-#include "ass_cache_template.h"
-
-typedef struct {
-    Bitmap *bm;               // the actual bitmaps
-    Bitmap *bm_o;
-    Bitmap *bm_s;
-} BitmapHashValue;
-
-Hashmap *ass_bitmap_cache_init(ASS_Library *library);
-void *cache_add_bitmap(Hashmap *, BitmapHashKey *key,
-                       BitmapHashValue *val);
-BitmapHashValue *cache_find_bitmap(Hashmap *bitmap_cache,
-                                   BitmapHashKey *key);
-Hashmap *ass_bitmap_cache_reset(Hashmap *bitmap_cache);
-void ass_bitmap_cache_done(Hashmap *bitmap_cache);
-
-
-typedef struct {
-    unsigned char *a;
-    unsigned char *b;
-} CompositeHashValue;
-
-Hashmap *ass_composite_cache_init(ASS_Library *library);
-void *cache_add_composite(Hashmap *, CompositeHashKey *key,
-                          CompositeHashValue *val);
-CompositeHashValue *cache_find_composite(Hashmap *composite_cache,
-                                         CompositeHashKey *key);
-Hashmap *ass_composite_cache_reset(Hashmap *composite_cache);
-void ass_composite_cache_done(Hashmap *composite_cache);
-
-
-typedef struct {
-    FT_Glyph glyph;
-    FT_Glyph outline_glyph;
-    FT_BBox bbox_scaled;        // bbox after scaling, but before rotation
-    FT_Vector advance;          // 26.6, advance distance to the next bitmap in line
-    int asc, desc;              // ascender/descender of a drawing
-} GlyphHashValue;
-
-Hashmap *ass_glyph_cache_init(ASS_Library *library);
-void *cache_add_glyph(Hashmap *, GlyphHashKey *key,
-                      GlyphHashValue *val);
-GlyphHashValue *cache_find_glyph(Hashmap *glyph_cache,
-                                 GlyphHashKey *key);
-Hashmap *ass_glyph_cache_reset(Hashmap *glyph_cache);
-void ass_glyph_cache_done(Hashmap *glyph_cache);
-
-#endif                          /* LIBASS_CACHE_H */
diff --git a/aegisub/libass/ass_cache_template.h b/aegisub/libass/ass_cache_template.h
deleted file mode 100644
index f335c6b27..000000000
--- a/aegisub/libass/ass_cache_template.h
+++ /dev/null
@@ -1,122 +0,0 @@
-#ifdef CREATE_STRUCT_DEFINITIONS
-#undef CREATE_STRUCT_DEFINITIONS
-#define START(funcname, structname) \
-    typedef struct structname {
-#define GENERIC(type, member) \
-        type member;
-#define FTVECTOR(member) \
-        FT_Vector member;
-#define BITMAPHASHKEY(member) \
-        BitmapHashKey member;
-#define END(typedefnamename) \
-    } typedefnamename;
-
-#elif defined(CREATE_COMPARISON_FUNCTIONS)
-#undef CREATE_COMPARISON_FUNCTIONS
-#define START(funcname, structname) \
-    static int funcname##_compare(void *key1, void *key2, size_t key_size) \
-    { \
-        struct structname *a = key1; \
-        struct structname *b = key2; \
-        return // conditions follow
-#define GENERIC(type, member) \
-            a->member == b->member &&
-#define FTVECTOR(member) \
-            a->member.x == b->member.x && a->member.y == b->member.y &&
-#define BITMAPHASHKEY(member) \
-            bitmap_compare(&a->member, &b->member, sizeof(a->member)) &&
-#define END(typedefname) \
-            1; \
-    }
-
-#elif defined(CREATE_HASH_FUNCTIONS)
-#undef CREATE_HASH_FUNCTIONS
-#define START(funcname, structname) \
-    static unsigned funcname##_hash(void *buf, size_t len) \
-    { \
-        struct structname *p = buf; \
-        unsigned hval = FNV1_32A_INIT;
-#define GENERIC(type, member) \
-        hval = fnv_32a_buf(&p->member, sizeof(p->member), hval);
-#define FTVECTOR(member) GENERIC(, member.x); GENERIC(, member.y);
-#define BITMAPHASHKEY(member) { \
-        unsigned temp = bitmap_hash(&p->member, sizeof(p->member)); \
-        hval = fnv_32a_buf(&temp, sizeof(temp), hval); \
-        }
-#define END(typedefname) \
-        return hval; \
-    }
-
-#else
-#error missing defines
-#endif
-
-
-
-// describes a bitmap; bitmaps with equivalents structs are considered identical
-START(bitmap, bitmap_hash_key)
-    GENERIC(char, bitmap) // bool : true = bitmap, false = outline
-    GENERIC(ASS_Font *, font)
-    GENERIC(double, size) // font size
-    GENERIC(uint32_t, ch) // character code
-    FTVECTOR(outline) // border width, 16.16 fixed point value
-    GENERIC(int, bold)
-    GENERIC(int, italic)
-    GENERIC(char, be) // blur edges
-    GENERIC(double, blur) // gaussian blur
-    GENERIC(unsigned, scale_x) // 16.16
-    GENERIC(unsigned, scale_y) // 16.16
-    GENERIC(int, frx) // signed 16.16
-    GENERIC(int, fry) // signed 16.16
-    GENERIC(int, frz) // signed 16.16
-    GENERIC(int, fax) // signed 16.16
-    GENERIC(int, fay) // signed 16.16
-    // shift vector that was added to glyph before applying rotation
-    // = 0, if frx = fry = frx = 0
-    // = (glyph base point) - (rotation origin), otherwise
-    GENERIC(int, shift_x)
-    GENERIC(int, shift_y)
-    FTVECTOR(advance) // subpixel shift vector
-    FTVECTOR(shadow_offset) // shadow subpixel shift
-    GENERIC(unsigned, drawing_hash) // hashcode of a drawing
-    GENERIC(unsigned, flags)    // glyph decoration
-    GENERIC(unsigned, border_style)
-END(BitmapHashKey)
-
-// describes an outline glyph
-START(glyph, glyph_hash_key)
-    GENERIC(ASS_Font *, font)
-    GENERIC(double, size) // font size
-    GENERIC(uint32_t, ch) // character code
-    GENERIC(int, bold)
-    GENERIC(int, italic)
-    GENERIC(unsigned, scale_x) // 16.16
-    GENERIC(unsigned, scale_y) // 16.16
-    FTVECTOR(outline) // border width, 16.16
-    GENERIC(unsigned, drawing_hash) // hashcode of a drawing
-    GENERIC(unsigned, flags)    // glyph decoration flags
-    GENERIC(unsigned, border_style)
-END(GlyphHashKey)
-
-// Cache for composited bitmaps
-START(composite, composite_hash_key)
-    GENERIC(int, aw)
-    GENERIC(int, ah)
-    GENERIC(int, bw)
-    GENERIC(int, bh)
-    GENERIC(int, ax)
-    GENERIC(int, ay)
-    GENERIC(int, bx)
-    GENERIC(int, by)
-    GENERIC(int, as)
-    GENERIC(int, bs)
-    GENERIC(unsigned char *, a)
-    GENERIC(unsigned char *, b)
-END(CompositeHashKey)
-
-
-#undef START
-#undef GENERIC
-#undef FTVECTOR
-#undef BITMAPHASHKEY
-#undef END
diff --git a/aegisub/libass/ass_drawing.c b/aegisub/libass/ass_drawing.c
deleted file mode 100644
index be430ddd9..000000000
--- a/aegisub/libass/ass_drawing.c
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include <ft2build.h>
-#include FT_GLYPH_H
-#include FT_OUTLINE_H
-#include FT_BBOX_H
-#include <math.h>
-
-#include "ass_utils.h"
-#include "ass_font.h"
-#include "ass_drawing.h"
-
-#define CURVE_ACCURACY 64.0
-#define GLYPH_INITIAL_POINTS 100
-#define GLYPH_INITIAL_CONTOURS 5
-
-/*
- * \brief Get and prepare a FreeType glyph
- */
-static void drawing_make_glyph(ASS_Drawing *drawing, void *fontconfig_priv,
-                               ASS_Font *font)
-{
-    FT_OutlineGlyph glyph;
-
-    // This is hacky...
-    glyph = (FT_OutlineGlyph) ass_font_get_glyph(fontconfig_priv, font,
-                                                 (uint32_t) ' ', 0, 0);
-    if (glyph) {
-        FT_Outline_Done(drawing->ftlibrary, &glyph->outline);
-        FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS,
-                       GLYPH_INITIAL_CONTOURS, &glyph->outline);
-
-        glyph->outline.n_contours = 0;
-        glyph->outline.n_points = 0;
-        glyph->root.advance.x = glyph->root.advance.y = 0;
-    }
-    drawing->glyph = glyph;
-}
-
-/*
- * \brief Add a single point to a contour.
- */
-static inline void drawing_add_point(ASS_Drawing *drawing,
-                                     FT_Vector *point)
-{
-    FT_Outline *ol = &drawing->glyph->outline;
-
-    if (ol->n_points >= drawing->max_points) {
-        drawing->max_points *= 2;
-        ol->points = realloc(ol->points, sizeof(FT_Vector) *
-                             drawing->max_points);
-        ol->tags = realloc(ol->tags, drawing->max_points);
-    }
-
-    ol->points[ol->n_points].x = point->x;
-    ol->points[ol->n_points].y = point->y;
-    ol->tags[ol->n_points] = 1;
-    ol->n_points++;
-}
-
-/*
- * \brief Close a contour and check glyph size overflow.
- */
-static inline void drawing_close_shape(ASS_Drawing *drawing)
-{
-    FT_Outline *ol = &drawing->glyph->outline;
-
-    if (ol->n_contours >= drawing->max_contours) {
-        drawing->max_contours *= 2;
-        ol->contours = realloc(ol->contours, sizeof(short) *
-                               drawing->max_contours);
-    }
-
-    if (ol->n_points) {
-        ol->contours[ol->n_contours] = ol->n_points - 1;
-        ol->n_contours++;
-    }
-}
-
-/*
- * \brief Prepare drawing for parsing.  This just sets a few parameters.
- */
-static void drawing_prepare(ASS_Drawing *drawing)
-{
-    // Scaling parameters
-    drawing->point_scale_x = drawing->scale_x *
-                             64.0 / (1 << (drawing->scale - 1));
-    drawing->point_scale_y = drawing->scale_y *
-                             64.0 / (1 << (drawing->scale - 1));
-}
-
-/*
- * \brief Finish a drawing.  This only sets the horizontal advance according
- * to the glyph's bbox at the moment.
- */
-static void drawing_finish(ASS_Drawing *drawing, int raw_mode)
-{
-    int i, offset;
-    FT_BBox bbox = drawing->cbox;
-    FT_Outline *ol = &drawing->glyph->outline;
-
-    // Close the last contour
-    drawing_close_shape(drawing);
-
-    ass_msg(drawing->library, MSGL_V,
-            "Parsed drawing with %d points and %d contours", ol->n_points,
-            ol->n_contours);
-
-    if (raw_mode)
-        return;
-
-    drawing->glyph->root.advance.x = d6_to_d16(bbox.xMax - bbox.xMin);
-
-    drawing->desc = double_to_d6(-drawing->pbo * drawing->scale_y);
-    drawing->asc = bbox.yMax - bbox.yMin + drawing->desc;
-
-    // Place it onto the baseline
-    offset = (bbox.yMax - bbox.yMin) + double_to_d6(-drawing->pbo *
-                                                    drawing->scale_y);
-    for (i = 0; i < ol->n_points; i++)
-        ol->points[i].y += offset;
-}
-
-/*
- * \brief Check whether a number of items on the list is available
- */
-static int token_check_values(ASS_DrawingToken *token, int i, int type)
-{
-    int j;
-    for (j = 0; j < i; j++) {
-        if (!token || token->type != type) return 0;
-        token = token->next;
-    }
-
-    return 1;
-}
-
-/*
- * \brief Tokenize a drawing string into a list of ASS_DrawingToken
- * This also expands points for closing b-splines
- */
-static ASS_DrawingToken *drawing_tokenize(char *str)
-{
-    char *p = str;
-    int i, val, type = -1, is_set = 0;
-    FT_Vector point = {0, 0};
-
-    ASS_DrawingToken *root = NULL, *tail = NULL, *spline_start = NULL;
-
-    while (*p) {
-        if (*p == 'c' && spline_start) {
-            // Close b-splines: add the first three points of the b-spline
-            // back to the end
-            if (token_check_values(spline_start->next, 2, TOKEN_B_SPLINE)) {
-                for (i = 0; i < 3; i++) {
-                    tail->next = calloc(1, sizeof(ASS_DrawingToken));
-                    tail->next->prev = tail;
-                    tail = tail->next;
-                    tail->type = TOKEN_B_SPLINE;
-                    tail->point = spline_start->point;
-                    spline_start = spline_start->next;
-                }
-                spline_start = NULL;
-            }
-        } else if (!is_set && mystrtoi(&p, &val)) {
-            point.x = val;
-            is_set = 1;
-            p--;
-        } else if (is_set == 1 && mystrtoi(&p, &val)) {
-            point.y = val;
-            is_set = 2;
-            p--;
-        } else if (*p == 'm')
-            type = TOKEN_MOVE;
-        else if (*p == 'n')
-            type = TOKEN_MOVE_NC;
-        else if (*p == 'l')
-            type = TOKEN_LINE;
-        else if (*p == 'b')
-            type = TOKEN_CUBIC_BEZIER;
-        else if (*p == 'q')
-            type = TOKEN_CONIC_BEZIER;
-        else if (*p == 's')
-            type = TOKEN_B_SPLINE;
-        // We're simply ignoring TOKEN_EXTEND_B_SPLINE here.
-        // This is not harmful at all, since it can be ommitted with
-        // similar result (the spline is extended anyway).
-
-        if (type != -1 && is_set == 2) {
-            if (root) {
-                tail->next = calloc(1, sizeof(ASS_DrawingToken));
-                tail->next->prev = tail;
-                tail = tail->next;
-            } else
-                root = tail = calloc(1, sizeof(ASS_DrawingToken));
-            tail->type = type;
-            tail->point = point;
-            is_set = 0;
-            if (type == TOKEN_B_SPLINE && !spline_start)
-                spline_start = tail->prev;
-        }
-        p++;
-    }
-
-    return root;
-}
-
-/*
- * \brief Free a list of tokens
- */
-static void drawing_free_tokens(ASS_DrawingToken *token)
-{
-    while (token) {
-        ASS_DrawingToken *at = token;
-        token = token->next;
-        free(at);
-    }
-}
-
-/*
- * \brief Update drawing cbox
- */
-static inline void update_cbox(ASS_Drawing *drawing, FT_Vector *point)
-{
-    FT_BBox *box = &drawing->cbox;
-
-    box->xMin = FFMIN(box->xMin, point->x);
-    box->xMax = FFMAX(box->xMax, point->x);
-    box->yMin = FFMIN(box->yMin, point->y);
-    box->yMax = FFMAX(box->yMax, point->y);
-}
-
-/*
- * \brief Translate and scale a point coordinate according to baseline
- * offset and scale.
- */
-static inline void translate_point(ASS_Drawing *drawing, FT_Vector *point)
-{
-    point->x = drawing->point_scale_x * point->x;
-    point->y = drawing->point_scale_y * -point->y;
-
-    update_cbox(drawing, point);
-}
-
-/*
- * \brief Evaluate a curve into lines
- * This curve evaluator is also used in VSFilter (RTS.cpp); it's a simple
- * implementation of the De Casteljau algorithm.
- */
-static void drawing_evaluate_curve(ASS_Drawing *drawing,
-                                   ASS_DrawingToken *token, char spline,
-                                   int started)
-{
-    double cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
-    double t, h, max_accel, max_accel1, max_accel2;
-    FT_Vector cur = {0, 0};
-    int x0, x1, x2, x3;
-    int y0, y1, y2, y3;
-
-    cur = token->point;
-    translate_point(drawing, &cur);
-    x0 = cur.x;
-    y0 = cur.y;
-    token = token->next;
-    cur = token->point;
-    translate_point(drawing, &cur);
-    x1 = cur.x;
-    y1 = cur.y;
-    token = token->next;
-    cur = token->point;
-    translate_point(drawing, &cur);
-    x2 = cur.x;
-    y2 = cur.y;
-    token = token->next;
-    cur = token->point;
-    translate_point(drawing, &cur);
-    x3 = cur.x;
-    y3 = cur.y;
-
-    if (spline) {
-        // 1   [-1 +3 -3 +1]
-        // - * [+3 -6 +3  0]
-        // 6   [-3  0 +3  0]
-        //	   [+1 +4 +1  0]
-
-        double div6 = 1.0/6.0;
-
-        cx3 = div6*(-  x0+3*x1-3*x2+x3);
-        cx2 = div6*( 3*x0-6*x1+3*x2);
-        cx1 = div6*(-3*x0	   +3*x2);
-        cx0 = div6*(   x0+4*x1+1*x2);
-
-        cy3 = div6*(-  y0+3*y1-3*y2+y3);
-        cy2 = div6*( 3*y0-6*y1+3*y2);
-        cy1 = div6*(-3*y0     +3*y2);
-        cy0 = div6*(   y0+4*y1+1*y2);
-    } else {
-        // [-1 +3 -3 +1]
-        // [+3 -6 +3  0]
-        // [-3 +3  0  0]
-        // [+1  0  0  0]
-
-        cx3 = -  x0+3*x1-3*x2+x3;
-        cx2 =  3*x0-6*x1+3*x2;
-        cx1 = -3*x0+3*x1;
-        cx0 =    x0;
-
-        cy3 = -  y0+3*y1-3*y2+y3;
-        cy2 =  3*y0-6*y1+3*y2;
-        cy1 = -3*y0+3*y1;
-        cy0 =    y0;
-    }
-
-    max_accel1 = fabs(2 * cy2) + fabs(6 * cy3);
-    max_accel2 = fabs(2 * cx2) + fabs(6 * cx3);
-
-    max_accel = FFMAX(max_accel1, max_accel2);
-    h = 1.0;
-
-    if (max_accel > CURVE_ACCURACY)
-        h = sqrt(CURVE_ACCURACY / max_accel);
-
-    if (!started) {
-        cur.x = cx0;
-        cur.y = cy0;
-        drawing_add_point(drawing, &cur);
-    }
-
-    for (t = 0; t < 1.0; t += h) {
-        cur.x = cx0 + t * (cx1 + t * (cx2 + t * cx3));
-        cur.y = cy0 + t * (cy1 + t * (cy2 + t * cy3));
-        drawing_add_point(drawing, &cur);
-    }
-
-    cur.x = cx0 + cx1 + cx2 + cx3;
-    cur.y = cy0 + cy1 + cy2 + cy3;
-    drawing_add_point(drawing, &cur);
-}
-
-/*
- * \brief Create and initialize a new drawing and return it
- */
-ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font,
-                             FT_Library lib)
-{
-    ASS_Drawing *drawing;
-
-    drawing = calloc(1, sizeof(*drawing));
-    drawing->text = calloc(1, DRAWING_INITIAL_SIZE);
-    drawing->size = DRAWING_INITIAL_SIZE;
-    drawing->cbox.xMin = drawing->cbox.yMin = INT_MAX;
-    drawing->cbox.xMax = drawing->cbox.yMax = INT_MIN;
-    drawing->fontconfig_priv = fontconfig_priv;
-    drawing->font = font;
-    drawing->ftlibrary = lib;
-    drawing->library = font->library;
-
-    drawing->scale_x = 1.;
-    drawing->scale_y = 1.;
-    drawing->max_contours = GLYPH_INITIAL_CONTOURS;
-    drawing->max_points = GLYPH_INITIAL_POINTS;
-
-    return drawing;
-}
-
-/*
- * \brief Free a drawing
- */
-void ass_drawing_free(ASS_Drawing* drawing)
-{
-    if (drawing) {
-        free(drawing->text);
-    }
-    free(drawing);
-}
-
-/*
- * \brief Add one ASCII character to the drawing text buffer
- */
-void ass_drawing_add_char(ASS_Drawing* drawing, char symbol)
-{
-    drawing->text[drawing->i++] = symbol;
-    drawing->text[drawing->i] = 0;
-
-    if (drawing->i + 1 >= drawing->size) {
-        drawing->size *= 2;
-        drawing->text = realloc(drawing->text, drawing->size);
-    }
-}
-
-/*
- * \brief Create a hashcode for the drawing
- * XXX: To avoid collisions a better hash algorithm might be useful.
- */
-void ass_drawing_hash(ASS_Drawing* drawing)
-{
-    drawing->hash = fnv_32a_str(drawing->text, FNV1_32A_INIT);
-}
-
-/*
- * \brief Convert token list to outline.  Calls the line and curve evaluators.
- */
-FT_OutlineGlyph *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode)
-{
-    int started = 0;
-    ASS_DrawingToken *token;
-    FT_Vector pen = {0, 0};
-
-    if (drawing->font)
-        drawing_make_glyph(drawing, drawing->fontconfig_priv, drawing->font);
-    if (!drawing->glyph)
-        return NULL;
-
-    drawing->tokens = drawing_tokenize(drawing->text);
-    drawing_prepare(drawing);
-
-    token = drawing->tokens;
-    while (token) {
-        // Draw something according to current command
-        switch (token->type) {
-        case TOKEN_MOVE_NC:
-            pen = token->point;
-            translate_point(drawing, &pen);
-            token = token->next;
-            break;
-        case TOKEN_MOVE:
-            pen = token->point;
-            translate_point(drawing, &pen);
-            if (started) {
-                drawing_close_shape(drawing);
-                started = 0;
-            }
-            token = token->next;
-            break;
-        case TOKEN_LINE: {
-            FT_Vector to;
-            to = token->point;
-            translate_point(drawing, &to);
-            if (!started) drawing_add_point(drawing, &pen);
-            drawing_add_point(drawing, &to);
-            started = 1;
-            token = token->next;
-            break;
-        }
-        case TOKEN_CUBIC_BEZIER:
-            if (token_check_values(token, 3, TOKEN_CUBIC_BEZIER) &&
-                token->prev) {
-                drawing_evaluate_curve(drawing, token->prev, 0, started);
-                token = token->next;
-                token = token->next;
-                token = token->next;
-                started = 1;
-            } else
-                token = token->next;
-            break;
-        case TOKEN_B_SPLINE:
-            if (token_check_values(token, 3, TOKEN_B_SPLINE) &&
-                token->prev) {
-                drawing_evaluate_curve(drawing, token->prev, 1, started);
-                token = token->next;
-                started = 1;
-            } else
-                token = token->next;
-            break;
-        default:
-            token = token->next;
-            break;
-        }
-    }
-
-    drawing_finish(drawing, raw_mode);
-    drawing_free_tokens(drawing->tokens);
-    return &drawing->glyph;
-}
diff --git a/aegisub/libass/ass_drawing.h b/aegisub/libass/ass_drawing.h
deleted file mode 100644
index f677fcddd..000000000
--- a/aegisub/libass/ass_drawing.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef LIBASS_DRAWING_H
-#define LIBASS_DRAWING_H
-
-#include <ft2build.h>
-#include FT_GLYPH_H
-
-#include "ass.h"
-
-#define DRAWING_INITIAL_SIZE 256
-
-typedef enum {
-    TOKEN_MOVE,
-    TOKEN_MOVE_NC,
-    TOKEN_LINE,
-    TOKEN_CUBIC_BEZIER,
-    TOKEN_CONIC_BEZIER,
-    TOKEN_B_SPLINE,
-    TOKEN_EXTEND_SPLINE,
-    TOKEN_CLOSE
-} ASS_TokenType;
-
-typedef struct ass_drawing_token {
-    ASS_TokenType type;
-    FT_Vector point;
-    struct ass_drawing_token *next;
-    struct ass_drawing_token *prev;
-} ASS_DrawingToken;
-
-typedef struct {
-    char *text; // drawing string
-    int i;      // text index
-    int scale;  // scale (1-64) for subpixel accuracy
-    double pbo; // drawing will be shifted in y direction by this amount
-    double scale_x;     // FontScaleX
-    double scale_y;     // FontScaleY
-    int asc;            // ascender
-    int desc;           // descender
-    FT_OutlineGlyph glyph;  // the "fake" glyph created for later rendering
-    int hash;           // hash value (for caching)
-
-    // private
-    FT_Library ftlibrary;   // needed for font ops
-    ASS_Font *font;         // dito
-    void *fontconfig_priv;  // dito
-    ASS_Library *library;
-    int size;           // current buffer size
-    ASS_DrawingToken *tokens;    // tokenized drawing
-    int max_points;     // current maximum size
-    int max_contours;
-    double point_scale_x;
-    double point_scale_y;
-    FT_BBox cbox;   // bounding box, or let's say... VSFilter's idea of it
-} ASS_Drawing;
-
-ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font,
-                             FT_Library lib);
-void ass_drawing_free(ASS_Drawing* drawing);
-void ass_drawing_add_char(ASS_Drawing* drawing, char symbol);
-void ass_drawing_hash(ASS_Drawing* drawing);
-FT_OutlineGlyph *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode);
-
-#endif /* LIBASS_DRAWING_H */
diff --git a/aegisub/libass/ass_font.c b/aegisub/libass/ass_font.c
deleted file mode 100644
index 0b8816a1b..000000000
--- a/aegisub/libass/ass_font.c
+++ /dev/null
@@ -1,701 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include <inttypes.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_SYNTHESIS_H
-#include FT_GLYPH_H
-#include FT_TRUETYPE_TABLES_H
-#include FT_OUTLINE_H
-#include <strings.h>
-
-#include "ass.h"
-#include "ass_library.h"
-#include "ass_font.h"
-#include "ass_bitmap.h"
-#include "ass_cache.h"
-#include "ass_fontconfig.h"
-#include "ass_utils.h"
-
-#define VERTICAL_LOWER_BOUND 0x02f1
-
-/**
- * Select a good charmap, prefer Microsoft Unicode charmaps.
- * Otherwise, let FreeType decide.
- */
-static void charmap_magic(ASS_Library *library, FT_Face face)
-{
-    int i;
-    int ms_cmap = -1;
-
-    // Search for a Microsoft Unicode cmap
-    for (i = 0; i < face->num_charmaps; ++i) {
-        FT_CharMap cmap = face->charmaps[i];
-        unsigned pid = cmap->platform_id;
-        unsigned eid = cmap->encoding_id;
-        if (pid == 3 /*microsoft */
-            && (eid == 1 /*unicode bmp */
-                || eid == 10 /*full unicode */ )) {
-            FT_Set_Charmap(face, cmap);
-            return;
-        } else if (pid == 3 && ms_cmap < 0)
-            ms_cmap = i;
-    }
-
-    // Try the first Microsoft cmap if no Microsoft Unicode cmap was found
-    if (ms_cmap >= 0) {
-        FT_CharMap cmap = face->charmaps[ms_cmap];
-        FT_Set_Charmap(face, cmap);
-        return;
-    }
-
-    if (!face->charmap) {
-        if (face->num_charmaps == 0) {
-            ass_msg(library, MSGL_WARN, "Font face with no charmaps");
-            return;
-        }
-        ass_msg(library, MSGL_WARN,
-                "No charmap autodetected, trying the first one");
-        FT_Set_Charmap(face, face->charmaps[0]);
-        return;
-    }
-}
-
-/**
- * \brief find a memory font by name
- */
-static int find_font(ASS_Library *library, char *name)
-{
-    int i;
-    for (i = 0; i < library->num_fontdata; ++i)
-        if (strcasecmp(name, library->fontdata[i].name) == 0)
-            return i;
-    return -1;
-}
-
-static void face_set_size(FT_Face face, double size);
-
-static void buggy_font_workaround(FT_Face face)
-{
-    // Some fonts have zero Ascender/Descender fields in 'hhea' table.
-    // In this case, get the information from 'os2' table or, as
-    // a last resort, from face.bbox.
-    if (face->ascender + face->descender == 0 || face->height == 0) {
-        TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
-        if (os2) {
-            face->ascender = os2->sTypoAscender;
-            face->descender = os2->sTypoDescender;
-            face->height = face->ascender - face->descender;
-        } else {
-            face->ascender = face->bbox.yMax;
-            face->descender = face->bbox.yMin;
-            face->height = face->ascender - face->descender;
-        }
-    }
-}
-
-/**
- * \brief Select a face with the given charcode and add it to ASS_Font
- * \return index of the new face in font->faces, -1 if failed
- */
-static int add_face(void *fc_priv, ASS_Font *font, uint32_t ch)
-{
-    char *path;
-    int index;
-    FT_Face face;
-    int error;
-    int mem_idx;
-
-    if (font->n_faces == ASS_FONT_MAX_FACES)
-        return -1;
-
-    path =
-        fontconfig_select(font->library, fc_priv, font->desc.family,
-                          font->desc.treat_family_as_pattern,
-                          font->desc.bold, font->desc.italic, &index, ch);
-    if (!path)
-        return -1;
-
-    mem_idx = find_font(font->library, path);
-    if (mem_idx >= 0) {
-        error =
-            FT_New_Memory_Face(font->ftlibrary,
-                               (unsigned char *) font->library->
-                               fontdata[mem_idx].data,
-                               font->library->fontdata[mem_idx].size, index,
-                               &face);
-        if (error) {
-            ass_msg(font->library, MSGL_WARN,
-                    "Error opening memory font: '%s'", path);
-            free(path);
-            return -1;
-        }
-    } else {
-        error = FT_New_Face(font->ftlibrary, path, index, &face);
-        if (error) {
-            ass_msg(font->library, MSGL_WARN,
-                    "Error opening font: '%s', %d", path, index);
-            free(path);
-            return -1;
-        }
-    }
-    charmap_magic(font->library, face);
-    buggy_font_workaround(face);
-
-    font->faces[font->n_faces++] = face;
-    face_set_size(face, font->size);
-    free(path);
-    return font->n_faces - 1;
-}
-
-/**
- * \brief Create a new ASS_Font according to "desc" argument
- */
-ASS_Font *ass_font_new(void *font_cache, ASS_Library *library,
-                       FT_Library ftlibrary, void *fc_priv,
-                       ASS_FontDesc *desc)
-{
-    int error;
-    ASS_Font *fontp;
-    ASS_Font font;
-
-    fontp = ass_font_cache_find((Hashmap *) font_cache, desc);
-    if (fontp)
-        return fontp;
-
-    font.library = library;
-    font.ftlibrary = ftlibrary;
-    font.n_faces = 0;
-    font.desc.family = strdup(desc->family);
-    font.desc.treat_family_as_pattern = desc->treat_family_as_pattern;
-    font.desc.bold = desc->bold;
-    font.desc.italic = desc->italic;
-    font.desc.vertical = desc->vertical;
-
-    font.scale_x = font.scale_y = 1.;
-    font.v.x = font.v.y = 0;
-    font.size = 0.;
-
-    error = add_face(fc_priv, &font, 0);
-    if (error == -1) {
-        free(font.desc.family);
-        return 0;
-    } else
-        return ass_font_cache_add((Hashmap *) font_cache, &font);
-}
-
-/**
- * \brief Set font transformation matrix and shift vector
- **/
-void ass_font_set_transform(ASS_Font *font, double scale_x,
-                            double scale_y, FT_Vector *v)
-{
-    font->scale_x = scale_x;
-    font->scale_y = scale_y;
-    if (v) {
-        font->v.x = v->x;
-        font->v.y = v->y;
-    }
-}
-
-static void face_set_size(FT_Face face, double size)
-{
-    TT_HoriHeader *hori = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
-    TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
-    double mscale = 1.;
-    FT_Size_RequestRec rq;
-    FT_Size_Metrics *m = &face->size->metrics;
-    // VSFilter uses metrics from TrueType OS/2 table
-    // The idea was borrowed from asa (http://asa.diac24.net)
-    if (hori && os2) {
-        int hori_height = hori->Ascender - hori->Descender;
-        int os2_height = os2->usWinAscent + os2->usWinDescent;
-        if (hori_height && os2_height)
-            mscale = (double) hori_height / os2_height;
-    }
-    memset(&rq, 0, sizeof(rq));
-    rq.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
-    rq.width = 0;
-    rq.height = double_to_d6(size * mscale);
-    rq.horiResolution = rq.vertResolution = 0;
-    FT_Request_Size(face, &rq);
-    m->ascender /= mscale;
-    m->descender /= mscale;
-    m->height /= mscale;
-}
-
-/**
- * \brief Set font size
- **/
-void ass_font_set_size(ASS_Font *font, double size)
-{
-    int i;
-    if (font->size != size) {
-        font->size = size;
-        for (i = 0; i < font->n_faces; ++i)
-            face_set_size(font->faces[i], size);
-    }
-}
-
-/**
- * \brief Get maximal font ascender and descender.
- * \param ch character code
- * The values are extracted from the font face that provides glyphs for the given character
- **/
-void ass_font_get_asc_desc(ASS_Font *font, uint32_t ch, int *asc,
-                           int *desc)
-{
-    int i;
-    for (i = 0; i < font->n_faces; ++i) {
-        FT_Face face = font->faces[i];
-        TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
-        if (FT_Get_Char_Index(face, ch)) {
-            int y_scale = face->size->metrics.y_scale;
-            if (os2) {
-                *asc = FT_MulFix(os2->usWinAscent, y_scale);
-                *desc = FT_MulFix(os2->usWinDescent, y_scale);
-            } else {
-                *asc = FT_MulFix(face->ascender, y_scale);
-                *desc = FT_MulFix(-face->descender, y_scale);
-            }
-            if (font->desc.vertical && ch >= VERTICAL_LOWER_BOUND) {
-                *asc = FT_MulFix(face->max_advance_width, y_scale);
-            }
-            return;
-        }
-    }
-
-    *asc = *desc = 0;
-}
-
-/*
- * Strike a glyph with a horizontal line; it's possible to underline it
- * and/or strike through it.  For the line's position and size, truetype
- * tables are consulted.  Obviously this relies on the data in the tables
- * being accurate.
- *
- */
-static int ass_strike_outline_glyph(FT_Face face, ASS_Font *font,
-                                    FT_Glyph glyph, int under, int through)
-{
-    TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
-    TT_Postscript *ps = FT_Get_Sfnt_Table(face, ft_sfnt_post);
-    FT_Outline *ol = &((FT_OutlineGlyph) glyph)->outline;
-    int bear, advance, y_scale, i, dir;
-
-    if (!under && !through)
-        return 0;
-
-    // Grow outline
-    i = (under ? 4 : 0) + (through ? 4 : 0);
-    ol->points = realloc(ol->points, sizeof(FT_Vector) *
-                         (ol->n_points + i));
-    ol->tags = realloc(ol->tags, ol->n_points + i);
-    i = !!under + !!through;
-    ol->contours = realloc(ol->contours, sizeof(short) *
-                           (ol->n_contours + i));
-
-    // If the bearing is negative, the glyph starts left of the current
-    // pen position
-    bear = FFMIN(face->glyph->metrics.horiBearingX, 0);
-    // We're adding half a pixel to avoid small gaps
-    advance = d16_to_d6(glyph->advance.x) + 32;
-    y_scale = face->size->metrics.y_scale;
-
-    // Reverse drawing direction for non-truetype fonts
-    dir = FT_Outline_Get_Orientation(ol);
-
-    // Add points to the outline
-    if (under && ps) {
-        int pos = FT_MulFix(ps->underlinePosition, y_scale * font->scale_y);
-        int size = FT_MulFix(ps->underlineThickness,
-                             y_scale * font->scale_y / 2);
-
-        FT_Vector points[4];
-
-        if (pos > 0 || size <= 0)
-            return 1;
-
-        points[0].x = bear;
-        points[0].y = pos + size;
-        points[1].x = advance;
-        points[1].y = pos + size;
-        points[2].x = advance;
-        points[2].y = pos - size;
-        points[3].x = bear;
-        points[3].y = pos - size;
-
-        if (dir == FT_ORIENTATION_TRUETYPE) {
-            for (i = 0; i < 4; i++) {
-                ol->points[ol->n_points] = points[i];
-                ol->tags[ol->n_points++] = 1;
-            }
-        } else {
-            for (i = 3; i >= 0; i--) {
-                ol->points[ol->n_points] = points[i];
-                ol->tags[ol->n_points++] = 1;
-            }
-        }
-
-        ol->contours[ol->n_contours++] = ol->n_points - 1;
-    }
-
-    if (through && os2) {
-        int pos = FT_MulFix(os2->yStrikeoutPosition, y_scale * font->scale_y);
-        int size = FT_MulFix(os2->yStrikeoutSize, y_scale * font->scale_y / 2);
-        FT_Vector points[4];
-
-        if (pos < 0 || size <= 0)
-            return 1;
-
-        points[0].x = bear;
-        points[0].y = pos + size;
-        points[1].x = advance;
-        points[1].y = pos + size;
-        points[2].x = advance;
-        points[2].y = pos - size;
-        points[3].x = bear;
-        points[3].y = pos - size;
-
-        if (dir == FT_ORIENTATION_TRUETYPE) {
-            for (i = 0; i < 4; i++) {
-                ol->points[ol->n_points] = points[i];
-                ol->tags[ol->n_points++] = 1;
-            }
-        } else {
-            for (i = 3; i >= 0; i--) {
-                ol->points[ol->n_points] = points[i];
-                ol->tags[ol->n_points++] = 1;
-            }
-        }
-
-        ol->contours[ol->n_contours++] = ol->n_points - 1;
-    }
-
-    return 0;
-}
-
-/**
- * Slightly embold a glyph without touching its metrics
- */
-static void ass_glyph_embolden(FT_GlyphSlot slot)
-{
-    int str;
-
-    if (slot->format != FT_GLYPH_FORMAT_OUTLINE)
-        return;
-
-    str = FT_MulFix(slot->face->units_per_EM,
-                    slot->face->size->metrics.y_scale) / 64;
-
-    FT_Outline_Embolden(&slot->outline, str);
-}
-
-/**
- * \brief Get a glyph
- * \param ch character code
- **/
-FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
-                            uint32_t ch, ASS_Hinting hinting, int deco)
-{
-    int error;
-    int index = 0;
-    int i;
-    FT_Glyph glyph;
-    FT_Face face = 0;
-    int flags = 0;
-    int vertical = font->desc.vertical;
-
-    if (ch < 0x20)
-        return 0;
-    // Handle NBSP like a regular space when rendering the glyph
-    if (ch == 0xa0)
-        ch = ' ';
-    if (font->n_faces == 0)
-        return 0;
-
-    for (i = 0; i < font->n_faces; ++i) {
-        face = font->faces[i];
-        index = FT_Get_Char_Index(face, ch);
-        if (index)
-            break;
-    }
-
-#ifdef CONFIG_FONTCONFIG
-    if (index == 0) {
-        int face_idx;
-        ass_msg(font->library, MSGL_INFO,
-                "Glyph 0x%X not found, selecting one more "
-                "font for (%s, %d, %d)", ch, font->desc.family,
-                font->desc.bold, font->desc.italic);
-        face_idx = add_face(fontconfig_priv, font, ch);
-        if (face_idx >= 0) {
-            face = font->faces[face_idx];
-            index = FT_Get_Char_Index(face, ch);
-            if (index == 0 && face->num_charmaps > 0) {
-                FT_CharMap cur = face->charmap;
-                ass_msg(font->library, MSGL_WARN,
-                    "Glyph 0x%X not found, falling back to first charmap", ch);
-                FT_Set_Charmap(face, face->charmaps[0]);
-                index = FT_Get_Char_Index(face, ch);
-                FT_Set_Charmap(face, cur);
-            }
-            if (index == 0) {
-                ass_msg(font->library, MSGL_ERR,
-                        "Glyph 0x%X not found in font for (%s, %d, %d)",
-                        ch, font->desc.family, font->desc.bold,
-                        font->desc.italic);
-            }
-        }
-    }
-#endif
-
-    flags = FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
-            | FT_LOAD_IGNORE_TRANSFORM;
-    switch (hinting) {
-    case ASS_HINTING_NONE:
-        flags |= FT_LOAD_NO_HINTING;
-        break;
-    case ASS_HINTING_LIGHT:
-        flags |= FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
-        break;
-    case ASS_HINTING_NORMAL:
-        flags |= FT_LOAD_FORCE_AUTOHINT;
-        break;
-    case ASS_HINTING_NATIVE:
-        break;
-    }
-
-    error = FT_Load_Glyph(face, index, flags);
-    if (error) {
-        ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d",
-                index);
-        return 0;
-    }
-    if (!(face->style_flags & FT_STYLE_FLAG_ITALIC) &&
-        (font->desc.italic > 55)) {
-        FT_GlyphSlot_Oblique(face->glyph);
-    }
-
-    if (!(face->style_flags & FT_STYLE_FLAG_BOLD) &&
-        (font->desc.bold > 80)) {
-        ass_glyph_embolden(face->glyph);
-    }
-    error = FT_Get_Glyph(face->glyph, &glyph);
-    if (error) {
-        ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d",
-                index);
-        return 0;
-    }
-
-    // Rotate glyph, if needed
-    if (vertical && ch >= VERTICAL_LOWER_BOUND) {
-        FT_Matrix m = { 0, double_to_d16(-1.0), double_to_d16(1.0), 0 };
-        FT_Outline_Transform(&((FT_OutlineGlyph) glyph)->outline, &m);
-        FT_Outline_Translate(&((FT_OutlineGlyph) glyph)->outline,
-                             face->glyph->metrics.vertAdvance,
-                             0);
-        glyph->advance.x = face->glyph->linearVertAdvance;
-    }
-
-    // Apply scaling and shift
-    {
-        FT_Matrix scale = { double_to_d16(font->scale_x), 0, 0,
-                            double_to_d16(font->scale_y) };
-        FT_Outline *outl = &((FT_OutlineGlyph) glyph)->outline;
-        FT_Outline_Transform(outl, &scale);
-        FT_Outline_Translate(outl, font->v.x, font->v.y);
-        glyph->advance.x *= font->scale_x;
-
-        ass_strike_outline_glyph(face, font, glyph, deco & DECO_UNDERLINE,
-                                 deco & DECO_STRIKETHROUGH);
-    }
-
-    return glyph;
-}
-
-/**
- * \brief Get kerning for the pair of glyphs.
- **/
-FT_Vector ass_font_get_kerning(ASS_Font *font, uint32_t c1, uint32_t c2)
-{
-    FT_Vector v = { 0, 0 };
-    int i;
-
-    if (font->desc.vertical)
-        return v;
-
-    for (i = 0; i < font->n_faces; ++i) {
-        FT_Face face = font->faces[i];
-        int i1 = FT_Get_Char_Index(face, c1);
-        int i2 = FT_Get_Char_Index(face, c2);
-        if (i1 && i2) {
-            if (FT_HAS_KERNING(face))
-                FT_Get_Kerning(face, i1, i2, FT_KERNING_DEFAULT, &v);
-            return v;
-        }
-        if (i1 || i2)           // these glyphs are from different font faces, no kerning information
-            return v;
-    }
-    return v;
-}
-
-/**
- * \brief Deallocate ASS_Font
- **/
-void ass_font_free(ASS_Font *font)
-{
-    int i;
-    for (i = 0; i < font->n_faces; ++i)
-        if (font->faces[i])
-            FT_Done_Face(font->faces[i]);
-    free(font->desc.family);
-    free(font);
-}
-
-/**
- * \brief Calculate the cbox of a series of points
- */
-static void
-get_contour_cbox(FT_BBox *box, FT_Vector *points, int start, int end)
-{
-    int i;
-    box->xMin = box->yMin = INT_MAX;
-    box->xMax = box->yMax = INT_MIN;
-
-    for (i = start; i <= end; i++) {
-        box->xMin = (points[i].x < box->xMin) ? points[i].x : box->xMin;
-        box->xMax = (points[i].x > box->xMax) ? points[i].x : box->xMax;
-        box->yMin = (points[i].y < box->yMin) ? points[i].y : box->yMin;
-        box->yMax = (points[i].y > box->yMax) ? points[i].y : box->yMax;
-    }
-}
-
-/**
- * \brief Determine winding direction of a contour
- * \return direction; 0 = clockwise
- */
-static int get_contour_direction(FT_Vector *points, int start, int end)
-{
-    int i;
-    long long sum = 0;
-    int x = points[start].x;
-    int y = points[start].y;
-    for (i = start + 1; i <= end; i++) {
-        sum += x * (points[i].y - y) - y * (points[i].x - x);
-        x = points[i].x;
-        y = points[i].y;
-    }
-    sum += x * (points[start].y - y) - y * (points[start].x - x);
-    return sum > 0;
-}
-
-/**
- * \brief Fix-up stroker result for huge borders by removing inside contours
- * that would reverse in size
- */
-void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, int border_y)
-{
-    int nc = glyph->outline.n_contours;
-    int begin, stop;
-    char modified = 0;
-    char *valid_cont = malloc(nc);
-    int start = 0;
-    int end = -1;
-    FT_BBox *boxes = malloc(nc * sizeof(FT_BBox));
-    int i, j;
-    int inside_direction;
-
-    inside_direction = FT_Outline_Get_Orientation(&glyph->outline) ==
-        FT_ORIENTATION_TRUETYPE;
-
-    // create a list of cboxes of the contours
-    for (i = 0; i < nc; i++) {
-        start = end + 1;
-        end = glyph->outline.contours[i];
-        get_contour_cbox(&boxes[i], glyph->outline.points, start, end);
-    }
-
-    // for each contour, check direction and whether it's "outside"
-    // or contained in another contour
-    end = -1;
-    for (i = 0; i < nc; i++) {
-        int dir;
-        start = end + 1;
-        end = glyph->outline.contours[i];
-        dir = get_contour_direction(glyph->outline.points, start, end);
-        valid_cont[i] = 1;
-        if (dir == inside_direction) {
-            for (j = 0; j < nc; j++) {
-                if (i == j)
-                    continue;
-                if (boxes[i].xMin >= boxes[j].xMin &&
-                    boxes[i].xMax <= boxes[j].xMax &&
-                    boxes[i].yMin >= boxes[j].yMin &&
-                    boxes[i].yMax <= boxes[j].yMax)
-                    goto check_inside;
-            }
-            /* "inside" contour but we can't find anything it could be
-             * inside of - assume the font is buggy and it should be
-             * an "outside" contour, and reverse it */
-            for (j = 0; j < (end + 1 - start) / 2; j++) {
-                FT_Vector temp = glyph->outline.points[start + j];
-                char temp2 = glyph->outline.tags[start + j];
-                glyph->outline.points[start + j] = glyph->outline.points[end - j];
-                glyph->outline.points[end - j] = temp;
-                glyph->outline.tags[start + j] = glyph->outline.tags[end - j];
-                glyph->outline.tags[end - j] = temp2;
-            }
-            dir ^= 1;
-        }
-        check_inside:
-        if (dir == inside_direction) {
-            FT_BBox box;
-            int width, height;
-            get_contour_cbox(&box, glyph->outline.points, start, end);
-            width = box.xMax - box.xMin;
-            height = box.yMax - box.yMin;
-            if (width < border_x * 2 || height < border_y * 2) {
-                valid_cont[i] = 0;
-                modified = 1;
-            }
-        }
-    }
-
-    // zero-out contours that can be removed; much simpler than copying
-    if (modified) {
-        for (i = 0; i < nc; i++) {
-            if (valid_cont[i])
-                continue;
-            begin = (i == 0) ? 0 : glyph->outline.contours[i - 1] + 1;
-            stop = glyph->outline.contours[i];
-            for (j = begin; j <= stop; j++) {
-                glyph->outline.points[j].x = 0;
-                glyph->outline.points[j].y = 0;
-                glyph->outline.tags[j] = 0;
-            }
-        }
-    }
-
-    free(boxes);
-    free(valid_cont);
-}
-
diff --git a/aegisub/libass/ass_font.h b/aegisub/libass/ass_font.h
deleted file mode 100644
index ab4054813..000000000
--- a/aegisub/libass/ass_font.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef LIBASS_FONT_H
-#define LIBASS_FONT_H
-
-#include <stdint.h>
-#include <ft2build.h>
-#include FT_GLYPH_H
-#include "ass.h"
-#include "ass_types.h"
-
-#define ASS_FONT_MAX_FACES 10
-#define DECO_UNDERLINE 1
-#define DECO_STRIKETHROUGH 2
-
-typedef struct {
-    char *family;
-    unsigned bold;
-    unsigned italic;
-    int treat_family_as_pattern;
-    int vertical;               // @font vertical layout
-} ASS_FontDesc;
-
-typedef struct {
-    ASS_FontDesc desc;
-    ASS_Library *library;
-    FT_Library ftlibrary;
-    FT_Face faces[ASS_FONT_MAX_FACES];
-    int n_faces;
-    double scale_x, scale_y;    // current transform
-    FT_Vector v;                // current shift
-    double size;
-} ASS_Font;
-
-// FIXME: passing the hashmap via a void pointer is very ugly.
-ASS_Font *ass_font_new(void *font_cache, ASS_Library *library,
-                       FT_Library ftlibrary, void *fc_priv,
-                       ASS_FontDesc *desc);
-void ass_font_set_transform(ASS_Font *font, double scale_x,
-                            double scale_y, FT_Vector *v);
-void ass_font_set_size(ASS_Font *font, double size);
-void ass_font_get_asc_desc(ASS_Font *font, uint32_t ch, int *asc,
-                           int *desc);
-FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
-                            uint32_t ch, ASS_Hinting hinting, int flags);
-FT_Vector ass_font_get_kerning(ASS_Font *font, uint32_t c1, uint32_t c2);
-void ass_font_free(ASS_Font *font);
-void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, int border_y);
-
-#endif                          /* LIBASS_FONT_H */
diff --git a/aegisub/libass/ass_fontconfig.c b/aegisub/libass/ass_fontconfig.c
deleted file mode 100644
index 2571739ff..000000000
--- a/aegisub/libass/ass_fontconfig.c
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-#include <strings.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <inttypes.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-#include "ass_utils.h"
-#include "ass.h"
-#include "ass_library.h"
-#include "ass_fontconfig.h"
-
-#ifdef CONFIG_FONTCONFIG
-#include <fontconfig/fontconfig.h>
-#include <fontconfig/fcfreetype.h>
-#endif
-
-struct fc_instance {
-#ifdef CONFIG_FONTCONFIG
-    FcConfig *config;
-#endif
-    char *family_default;
-    char *path_default;
-    int index_default;
-};
-
-#ifdef CONFIG_FONTCONFIG
-
-/**
- * \brief Case-insensitive match ASS/SSA font family against full name. (also
- * known as "name for humans")
- *
- * \param lib library instance
- * \param priv fontconfig instance
- * \param family font fullname
- * \param bold weight attribute
- * \param italic italic attribute
- * \return font set
- */
-static FcFontSet *
-match_fullname(ASS_Library *lib, FCInstance *priv, const char *family,
-               unsigned bold, unsigned italic)
-{
-    FcFontSet *sets[2];
-    FcFontSet *result = FcFontSetCreate();
-    int nsets = 0;
-    int i, fi;
-
-    if ((sets[nsets] = FcConfigGetFonts(priv->config, FcSetSystem)))
-        nsets++;
-    if ((sets[nsets] = FcConfigGetFonts(priv->config, FcSetApplication)))
-        nsets++;
-
-    // Run over font sets and patterns and try to match against full name
-    for (i = 0; i < nsets; i++) {
-        FcFontSet *set = sets[i];
-        for (fi = 0; fi < set->nfont; fi++) {
-            FcPattern *pat = set->fonts[fi];
-            char *fullname;
-            int pi = 0, at;
-            FcBool ol;
-            while (FcPatternGetString(pat, FC_FULLNAME, pi++,
-                   (FcChar8 **) &fullname) == FcResultMatch) {
-                if (FcPatternGetBool(pat, FC_OUTLINE, 0, &ol) != FcResultMatch
-                    || ol != FcTrue)
-                    continue;
-                if (FcPatternGetInteger(pat, FC_SLANT, 0, &at) != FcResultMatch
-                    || at < italic)
-                    continue;
-                if (FcPatternGetInteger(pat, FC_WEIGHT, 0, &at) != FcResultMatch
-                    || at < bold)
-                    continue;
-                if (strcasecmp(fullname, family) == 0) {
-                    FcFontSetAdd(result, FcPatternDuplicate(pat));
-                    break;
-                }
-            }
-        }
-    }
-
-    return result;
-}
-
-/**
- * \brief Low-level font selection.
- * \param priv private data
- * \param family font family
- * \param treat_family_as_pattern treat family as fontconfig pattern
- * \param bold font weight value
- * \param italic font slant value
- * \param index out: font index inside a file
- * \param code: the character that should be present in the font, can be 0
- * \return font file path
-*/
-static char *select_font(ASS_Library *library, FCInstance *priv,
-                          const char *family, int treat_family_as_pattern,
-                          unsigned bold, unsigned italic, int *index,
-                          uint32_t code)
-{
-    FcBool rc;
-    FcResult result;
-    FcPattern *pat = NULL, *rpat = NULL;
-    int r_index, r_slant, r_weight;
-    FcChar8 *r_family, *r_style, *r_file, *r_fullname;
-    FcBool r_outline, r_embolden;
-    FcCharSet *r_charset;
-    FcFontSet *ffullname = NULL, *fsorted = NULL, *fset = NULL;
-    int curf;
-    char *retval = NULL;
-    int family_cnt = 0;
-
-    *index = 0;
-
-    if (treat_family_as_pattern)
-        pat = FcNameParse((const FcChar8 *) family);
-    else
-        pat = FcPatternCreate();
-
-    if (!pat)
-        goto error;
-
-    if (!treat_family_as_pattern) {
-        FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) family);
-
-        // In SSA/ASS fonts are sometimes referenced by their "full name",
-        // which is usually a concatenation of family name and font
-        // style (ex. Ottawa Bold). Full name is available from
-        // FontConfig pattern element FC_FULLNAME, but it is never
-        // used for font matching.
-        // Therefore, I'm removing words from the end of the name one
-        // by one, and adding shortened names to the pattern. It seems
-        // that the first value (full name in this case) has
-        // precedence in matching.
-        // An alternative approach could be to reimplement FcFontSort
-        // using FC_FULLNAME instead of FC_FAMILY.
-        family_cnt = 1;
-        {
-            char *s = strdup(family);
-            char *p = s + strlen(s);
-            while (--p > s)
-                if (*p == ' ' || *p == '-') {
-                    *p = '\0';
-                    FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) s);
-                    ++family_cnt;
-                }
-            free(s);
-        }
-    }
-    FcPatternAddBool(pat, FC_OUTLINE, FcTrue);
-    FcPatternAddInteger(pat, FC_SLANT, italic);
-    FcPatternAddInteger(pat, FC_WEIGHT, bold);
-
-    FcDefaultSubstitute(pat);
-
-    rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern);
-    if (!rc)
-        goto error;
-
-    fsorted = FcFontSort(priv->config, pat, FcTrue, NULL, &result);
-    ffullname = match_fullname(library, priv, family, bold, italic);
-    if (!fsorted || !ffullname)
-        goto error;
-
-    fset = FcFontSetCreate();
-    for (curf = 0; curf < ffullname->nfont; ++curf) {
-        FcPattern *curp = ffullname->fonts[curf];
-        FcPatternReference(curp);
-        FcFontSetAdd(fset, curp);
-    }
-    for (curf = 0; curf < fsorted->nfont; ++curf) {
-        FcPattern *curp = fsorted->fonts[curf];
-        FcPatternReference(curp);
-        FcFontSetAdd(fset, curp);
-    }
-
-    for (curf = 0; curf < fset->nfont; ++curf) {
-        FcPattern *curp = fset->fonts[curf];
-
-        result = FcPatternGetBool(curp, FC_OUTLINE, 0, &r_outline);
-        if (result != FcResultMatch)
-            continue;
-        if (r_outline != FcTrue)
-            continue;
-        if (!code)
-            break;
-        result = FcPatternGetCharSet(curp, FC_CHARSET, 0, &r_charset);
-        if (result != FcResultMatch)
-            continue;
-        if (FcCharSetHasChar(r_charset, code))
-            break;
-    }
-
-    if (curf >= fset->nfont)
-        goto error;
-
-    if (!treat_family_as_pattern) {
-        // Remove all extra family names from original pattern.
-        // After this, FcFontRenderPrepare will select the most relevant family
-        // name in case there are more than one of them.
-        for (; family_cnt > 1; --family_cnt)
-            FcPatternRemove(pat, FC_FAMILY, family_cnt - 1);
-    }
-
-    rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]);
-    if (!rpat)
-        goto error;
-
-    result = FcPatternGetInteger(rpat, FC_INDEX, 0, &r_index);
-    if (result != FcResultMatch)
-        goto error;
-    *index = r_index;
-
-    result = FcPatternGetString(rpat, FC_FILE, 0, &r_file);
-    if (result != FcResultMatch)
-        goto error;
-    retval = strdup((const char *) r_file);
-
-    result = FcPatternGetString(rpat, FC_FAMILY, 0, &r_family);
-    if (result != FcResultMatch)
-        r_family = NULL;
-
-    result = FcPatternGetString(rpat, FC_FULLNAME, 0, &r_fullname);
-    if (result != FcResultMatch)
-        r_fullname = NULL;
-
-    if (!treat_family_as_pattern &&
-        !(r_family && strcasecmp((const char *) r_family, family) == 0) &&
-        !(r_fullname && strcasecmp((const char *) r_fullname, family) == 0))
-        ass_msg(library, MSGL_WARN,
-               "fontconfig: Selected font is not the requested one: "
-               "'%s' != '%s'",
-               (const char *) (r_fullname ? r_fullname : r_family), family);
-
-    result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style);
-    if (result != FcResultMatch)
-        r_style = NULL;
-
-    result = FcPatternGetInteger(rpat, FC_SLANT, 0, &r_slant);
-    if (result != FcResultMatch)
-        r_slant = 0;
-
-    result = FcPatternGetInteger(rpat, FC_WEIGHT, 0, &r_weight);
-    if (result != FcResultMatch)
-        r_weight = 0;
-
-    result = FcPatternGetBool(rpat, FC_EMBOLDEN, 0, &r_embolden);
-    if (result != FcResultMatch)
-        r_embolden = 0;
-
-    ass_msg(library, MSGL_V,
-           "Font info: family '%s', style '%s', fullname '%s',"
-           " slant %d, weight %d%s", (const char *) r_family,
-           (const char *) r_style, (const char *) r_fullname, r_slant,
-           r_weight, r_embolden ? ", embolden" : "");
-
-  error:
-    if (pat)
-        FcPatternDestroy(pat);
-    if (rpat)
-        FcPatternDestroy(rpat);
-    if (fsorted)
-        FcFontSetDestroy(fsorted);
-    if (ffullname)
-        FcFontSetDestroy(ffullname);
-    if (fset)
-        FcFontSetDestroy(fset);
-    return retval;
-}
-
-/**
- * \brief Find a font. Use default family or path if necessary.
- * \param priv_ private data
- * \param family font family
- * \param treat_family_as_pattern treat family as fontconfig pattern
- * \param bold font weight value
- * \param italic font slant value
- * \param index out: font index inside a file
- * \param code: the character that should be present in the font, can be 0
- * \return font file path
-*/
-char *fontconfig_select(ASS_Library *library, FCInstance *priv,
-                        const char *family, int treat_family_as_pattern,
-                        unsigned bold, unsigned italic, int *index,
-                        uint32_t code)
-{
-    char *res = 0;
-    if (!priv->config) {
-        *index = priv->index_default;
-        res = priv->path_default ? strdup(priv->path_default) : 0;
-        return res;
-    }
-    if (family && *family)
-        res =
-            select_font(library, priv, family, treat_family_as_pattern,
-                         bold, italic, index, code);
-    if (!res && priv->family_default) {
-        res =
-            select_font(library, priv, priv->family_default, 0, bold,
-                         italic, index, code);
-        if (res)
-            ass_msg(library, MSGL_WARN, "fontconfig_select: Using default "
-                    "font family: (%s, %d, %d) -> %s, %d",
-                    family, bold, italic, res, *index);
-    }
-    if (!res && priv->path_default) {
-        res = strdup(priv->path_default);
-        *index = priv->index_default;
-        ass_msg(library, MSGL_WARN, "fontconfig_select: Using default font: "
-                "(%s, %d, %d) -> %s, %d", family, bold, italic,
-                res, *index);
-    }
-    if (!res) {
-        res = select_font(library, priv, "Arial", 0, bold, italic,
-                           index, code);
-        if (res)
-            ass_msg(library, MSGL_WARN, "fontconfig_select: Using 'Arial' "
-                    "font family: (%s, %d, %d) -> %s, %d", family, bold,
-                    italic, res, *index);
-    }
-    if (res)
-        ass_msg(library, MSGL_V,
-                "fontconfig_select: (%s, %d, %d) -> %s, %d", family, bold,
-                italic, res, *index);
-    return res;
-}
-
-/**
- * \brief Process memory font.
- * \param priv private data
- * \param library library object
- * \param ftlibrary freetype library object
- * \param idx index of the processed font in library->fontdata
- *
- * Builds a font pattern in memory via FT_New_Memory_Face/FcFreeTypeQueryFace.
-*/
-static void process_fontdata(FCInstance *priv, ASS_Library *library,
-                             FT_Library ftlibrary, int idx)
-{
-    int rc;
-    const char *name = library->fontdata[idx].name;
-    const char *data = library->fontdata[idx].data;
-    int data_size = library->fontdata[idx].size;
-
-    FT_Face face;
-    FcPattern *pattern;
-    FcFontSet *fset;
-    FcBool res;
-    int face_index, num_faces = 1;
-
-    for (face_index = 0; face_index < num_faces; ++face_index) {
-        rc = FT_New_Memory_Face(ftlibrary, (unsigned char *) data,
-                                data_size, face_index, &face);
-        if (rc) {
-            ass_msg(library, MSGL_WARN, "Error opening memory font: %s",
-                   name);
-            return;
-        }
-        num_faces = face->num_faces;
-
-        pattern =
-            FcFreeTypeQueryFace(face, (unsigned char *) name, face_index,
-                                FcConfigGetBlanks(priv->config));
-        if (!pattern) {
-            ass_msg(library, MSGL_WARN, "%s failed", "FcFreeTypeQueryFace");
-            FT_Done_Face(face);
-            return;
-        }
-
-        fset = FcConfigGetFonts(priv->config, FcSetSystem);     // somehow it failes when asked for FcSetApplication
-        if (!fset) {
-            ass_msg(library, MSGL_WARN, "%s failed", "FcConfigGetFonts");
-            FT_Done_Face(face);
-            return;
-        }
-
-        res = FcFontSetAdd(fset, pattern);
-        if (!res) {
-            ass_msg(library, MSGL_WARN, "%s failed", "FcFontSetAdd");
-            FT_Done_Face(face);
-            return;
-        }
-
-        FT_Done_Face(face);
-    }
-}
-
-/**
- * \brief Init fontconfig.
- * \param library libass library object
- * \param ftlibrary freetype library object
- * \param family default font family
- * \param path default font path
- * \param fc whether fontconfig should be used
- * \param config path to a fontconfig configuration file, or NULL
- * \param update whether the fontconfig cache should be built/updated
- * \return pointer to fontconfig private data
-*/
-FCInstance *fontconfig_init(ASS_Library *library,
-                            FT_Library ftlibrary, const char *family,
-                            const char *path, int fc, const char *config,
-                            int update)
-{
-    int rc;
-    FCInstance *priv = calloc(1, sizeof(FCInstance));
-    const char *dir = library->fonts_dir;
-    int i;
-
-    if (!fc) {
-        ass_msg(library, MSGL_WARN,
-               "Fontconfig disabled, only default font will be used.");
-        goto exit;
-    }
-
-    priv->config = FcConfigCreate();
-    rc = FcConfigParseAndLoad(priv->config, (unsigned char *) config, FcTrue);
-    if (!rc) {
-        ass_msg(library, MSGL_WARN, "No usable fontconfig configuration "
-                "file found, using fallback.");
-        FcConfigDestroy(priv->config);
-        priv->config = FcInitLoadConfig();
-        rc++;
-    }
-    if (rc && update) {
-        FcConfigBuildFonts(priv->config);
-    }
-
-    if (!rc || !priv->config) {
-        ass_msg(library, MSGL_FATAL,
-                "No valid fontconfig configuration found!");
-        FcConfigDestroy(priv->config);
-        goto exit;
-    }
-
-    for (i = 0; i < library->num_fontdata; ++i)
-        process_fontdata(priv, library, ftlibrary, i);
-
-    if (dir) {
-        ass_msg(library, MSGL_V, "Updating font cache");
-
-        rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir);
-        if (!rc) {
-            ass_msg(library, MSGL_WARN, "%s failed", "FcConfigAppFontAddDir");
-        }
-    }
-
-    priv->family_default = family ? strdup(family) : NULL;
-exit:
-    priv->path_default = path ? strdup(path) : NULL;
-    priv->index_default = 0;
-
-    return priv;
-}
-
-int fontconfig_update(FCInstance *priv)
-{
-        return FcConfigBuildFonts(priv->config);
-}
-
-#else                           /* CONFIG_FONTCONFIG */
-
-char *fontconfig_select(ASS_Library *library, FCInstance *priv,
-                        const char *family, int treat_family_as_pattern,
-                        unsigned bold, unsigned italic, int *index,
-                        uint32_t code)
-{
-    *index = priv->index_default;
-    char* res = priv->path_default ? strdup(priv->path_default) : 0;
-    return res;
-}
-
-FCInstance *fontconfig_init(ASS_Library *library,
-                            FT_Library ftlibrary, const char *family,
-                            const char *path, int fc, const char *config,
-                            int update)
-{
-    FCInstance *priv;
-
-    ass_msg(library, MSGL_WARN,
-        "Fontconfig disabled, only default font will be used.");
-
-    priv = calloc(1, sizeof(FCInstance));
-
-    priv->path_default = path ? strdup(path) : 0;
-    priv->index_default = 0;
-    return priv;
-}
-
-int fontconfig_update(FCInstance *priv)
-{
-    // Do nothing
-    return 1;
-}
-
-#endif
-
-void fontconfig_done(FCInstance *priv)
-{
-
-    if (priv) {
-#ifdef CONFIG_FONTCONFIG
-        FcConfigDestroy(priv->config);
-#endif
-        free(priv->path_default);
-        free(priv->family_default);
-    }
-    free(priv);
-}
diff --git a/aegisub/libass/ass_fontconfig.h b/aegisub/libass/ass_fontconfig.h
deleted file mode 100644
index 396fb72d0..000000000
--- a/aegisub/libass/ass_fontconfig.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef LIBASS_FONTCONFIG_H
-#define LIBASS_FONTCONFIG_H
-
-#include <stdint.h>
-#include "ass_types.h"
-#include "ass.h"
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-#ifdef CONFIG_FONTCONFIG
-#include <fontconfig/fontconfig.h>
-#endif
-
-typedef struct fc_instance FCInstance;
-
-FCInstance *fontconfig_init(ASS_Library *library,
-                            FT_Library ftlibrary, const char *family,
-                            const char *path, int fc, const char *config,
-                            int update);
-char *fontconfig_select(ASS_Library *library, FCInstance *priv,
-                        const char *family, int treat_family_as_pattern,
-                        unsigned bold, unsigned italic, int *index,
-                        uint32_t code);
-void fontconfig_done(FCInstance *priv);
-int fontconfig_update(FCInstance *priv);
-
-#endif                          /* LIBASS_FONTCONFIG_H */
diff --git a/aegisub/libass/ass_library.c b/aegisub/libass/ass_library.c
deleted file mode 100644
index 5bca64485..000000000
--- a/aegisub/libass/ass_library.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-#include "ass.h"
-#include "ass_library.h"
-#include "ass_utils.h"
-
-static void ass_msg_handler(int level, const char *fmt, va_list va, void *data)
-{
-    if (level > MSGL_INFO)
-        return;
-    fprintf(stderr, "[ass] ");
-    vfprintf(stderr, fmt, va);
-    fprintf(stderr, "\n");
-}
-
-ASS_Library *ass_library_init(void)
-{
-    ASS_Library* lib = calloc(1, sizeof(*lib));
-    lib->msg_callback = ass_msg_handler;
-
-    return lib;
-}
-
-void ass_library_done(ASS_Library *priv)
-{
-    if (priv) {
-        ass_set_fonts_dir(priv, NULL);
-        ass_set_style_overrides(priv, NULL);
-        ass_clear_fonts(priv);
-        free(priv);
-    }
-}
-
-void ass_set_fonts_dir(ASS_Library *priv, const char *fonts_dir)
-{
-    free(priv->fonts_dir);
-
-    priv->fonts_dir = fonts_dir ? strdup(fonts_dir) : 0;
-}
-
-void ass_set_extract_fonts(ASS_Library *priv, int extract)
-{
-    priv->extract_fonts = !!extract;
-}
-
-void ass_set_style_overrides(ASS_Library *priv, char **list)
-{
-    char **p;
-    char **q;
-    int cnt;
-
-    if (priv->style_overrides) {
-        for (p = priv->style_overrides; *p; ++p)
-            free(*p);
-    }
-    free(priv->style_overrides);
-
-    if (!list)
-        return;
-
-    for (p = list, cnt = 0; *p; ++p, ++cnt) {
-    }
-
-    priv->style_overrides = malloc((cnt + 1) * sizeof(char *));
-    for (p = list, q = priv->style_overrides; *p; ++p, ++q)
-        *q = strdup(*p);
-    priv->style_overrides[cnt] = NULL;
-}
-
-static void grow_array(void **array, int nelem, size_t elsize)
-{
-    if (!(nelem & 31))
-        *array = realloc(*array, (nelem + 32) * elsize);
-}
-
-void ass_add_font(ASS_Library *priv, char *name, char *data, int size)
-{
-    int idx = priv->num_fontdata;
-    if (!name || !data || !size)
-        return;
-    grow_array((void **) &priv->fontdata, priv->num_fontdata,
-               sizeof(*priv->fontdata));
-
-    priv->fontdata[idx].name = strdup(name);
-
-    priv->fontdata[idx].data = malloc(size);
-    memcpy(priv->fontdata[idx].data, data, size);
-
-    priv->fontdata[idx].size = size;
-
-    priv->num_fontdata++;
-}
-
-void ass_clear_fonts(ASS_Library *priv)
-{
-    int i;
-    for (i = 0; i < priv->num_fontdata; ++i) {
-        free(priv->fontdata[i].name);
-        free(priv->fontdata[i].data);
-    }
-    free(priv->fontdata);
-    priv->fontdata = NULL;
-    priv->num_fontdata = 0;
-}
-
-/*
- * Register a message callback function with libass.  Without setting one,
- * a default handler is used which prints everything with MSGL_INFO or
- * higher to the standard output.
- *
- * \param msg_cb the callback function
- * \param data additional data that will be passed to the callback
- */
-void ass_set_message_cb(ASS_Library *priv,
-                        void (*msg_cb)(int, const char *, va_list, void *),
-                        void *data)
-{
-    if (msg_cb) {
-        priv->msg_callback = msg_cb;
-        priv->msg_callback_data = data;
-    }
-}
diff --git a/aegisub/libass/ass_library.h b/aegisub/libass/ass_library.h
deleted file mode 100644
index 8faf15e93..000000000
--- a/aegisub/libass/ass_library.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef LIBASS_LIBRARY_H
-#define LIBASS_LIBRARY_H
-
-#include <stdarg.h>
-
-typedef struct {
-    char *name;
-    char *data;
-    int size;
-} ASS_Fontdata;
-
-struct ass_library {
-    char *fonts_dir;
-    int extract_fonts;
-    char **style_overrides;
-
-    ASS_Fontdata *fontdata;
-    int num_fontdata;
-    void (*msg_callback)(int, const char *, va_list, void *);
-    void *msg_callback_data;
-};
-
-#endif                          /* LIBASS_LIBRARY_H */
diff --git a/aegisub/libass/ass_parse.c b/aegisub/libass/ass_parse.c
deleted file mode 100644
index 40aaf0430..000000000
--- a/aegisub/libass/ass_parse.c
+++ /dev/null
@@ -1,943 +0,0 @@
-/*
- * Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "ass_render.h"
-#include "ass_parse.h"
-
-#define MAX_BE 127
-#define NBSP 0xa0   // unicode non-breaking space character
-
-#define skip_to(x) while ((*p != (x)) && (*p != '}') && (*p != 0)) { ++p;}
-#define skip(x) if (*p == (x)) ++p; else { return p; }
-#define skipopt(x) if (*p == (x)) { ++p; }
-
-/**
- * \brief Check if starting part of (*p) matches sample.
- * If true, shift p to the first symbol after the matching part.
- */
-static inline int mystrcmp(char **p, const char *sample)
-{
-    int len = strlen(sample);
-    if (strncmp(*p, sample, len) == 0) {
-        (*p) += len;
-        return 1;
-    } else
-        return 0;
-}
-
-static void change_font_size(ASS_Renderer *render_priv, double sz)
-{
-    double size = sz * render_priv->font_scale;
-
-    if (size < 1)
-        size = 1;
-    else if (size > render_priv->height * 2)
-        size = render_priv->height * 2;
-
-    ass_font_set_size(render_priv->state.font, size);
-
-    render_priv->state.font_size = sz;
-}
-
-/**
- * \brief Change current font, using setting from render_priv->state.
- */
-void update_font(ASS_Renderer *render_priv)
-{
-    unsigned val;
-    ASS_FontDesc desc;
-    desc.treat_family_as_pattern = render_priv->state.treat_family_as_pattern;
-
-    if (render_priv->state.family[0] == '@') {
-        desc.vertical = 1;
-        desc.family = strdup(render_priv->state.family + 1);
-    } else {
-        desc.vertical = 0;
-        desc.family = strdup(render_priv->state.family);
-    }
-
-    val = render_priv->state.bold;
-    // 0 = normal, 1 = bold, >1 = exact weight
-    if (val == 1 || val == -1)
-        val = 200;              // bold
-    else if (val <= 0)
-        val = 80;               // normal
-    desc.bold = val;
-
-    val = render_priv->state.italic;
-    if (val == 1 || val == -1)
-        val = 110;              // italic
-    else if (val <= 0)
-        val = 0;                // normal
-    desc.italic = val;
-
-    render_priv->state.font =
-        ass_font_new(render_priv->cache.font_cache, render_priv->library,
-                     render_priv->ftlibrary, render_priv->fontconfig_priv,
-                     &desc);
-    free(desc.family);
-
-    if (render_priv->state.font)
-        change_font_size(render_priv, render_priv->state.font_size);
-}
-
-/**
- * \brief Change border width
- * negative value resets border to style value
- */
-void change_border(ASS_Renderer *render_priv, double border_x,
-                   double border_y)
-{
-    int bord;
-    if (!render_priv->state.font)
-        return;
-
-    if (border_x < 0 && border_y < 0) {
-        if (render_priv->state.style->BorderStyle == 1 ||
-            render_priv->state.style->BorderStyle == 3)
-            border_x = border_y = render_priv->state.style->Outline;
-        else
-            border_x = border_y = 1.;
-    }
-
-    render_priv->state.border_x = border_x;
-    render_priv->state.border_y = border_y;
-
-    bord = 64 * border_x * render_priv->border_scale;
-    if (bord > 0 && border_x == border_y) {
-        if (!render_priv->state.stroker) {
-            int error;
-            error =
-                FT_Stroker_New(render_priv->ftlibrary,
-                               &render_priv->state.stroker);
-            if (error) {
-                ass_msg(render_priv->library, MSGL_V,
-                        "failed to get stroker");
-                render_priv->state.stroker = 0;
-            }
-        }
-        if (render_priv->state.stroker)
-            FT_Stroker_Set(render_priv->state.stroker, bord,
-                           FT_STROKER_LINECAP_ROUND,
-                           FT_STROKER_LINEJOIN_ROUND, 0);
-    } else {
-        FT_Stroker_Done(render_priv->state.stroker);
-        render_priv->state.stroker = 0;
-    }
-}
-
-/**
- * \brief Calculate a weighted average of two colors
- * calculates c1*(1-a) + c2*a, but separately for each component except alpha
- */
-static void change_color(uint32_t *var, uint32_t new, double pwr)
-{
-    (*var) = ((uint32_t) (_r(*var) * (1 - pwr) + _r(new) * pwr) << 24) +
-        ((uint32_t) (_g(*var) * (1 - pwr) + _g(new) * pwr) << 16) +
-        ((uint32_t) (_b(*var) * (1 - pwr) + _b(new) * pwr) << 8) + _a(*var);
-}
-
-// like change_color, but for alpha component only
-inline void change_alpha(uint32_t *var, uint32_t new, double pwr)
-{
-    *var =
-        (_r(*var) << 24) + (_g(*var) << 16) + (_b(*var) << 8) +
-        (uint32_t) (_a(*var) * (1 - pwr) + _a(new) * pwr);
-}
-
-/**
- * \brief Multiply two alpha values
- * \param a first value
- * \param b second value
- * \return result of multiplication
- * Parameters and result are limited by 0xFF.
- */
-inline uint32_t mult_alpha(uint32_t a, uint32_t b)
-{
-    return 0xFF - (0xFF - a) * (0xFF - b) / 0xFF;
-}
-
-/**
- * \brief Calculate alpha value by piecewise linear function
- * Used for \fad, \fade implementation.
- */
-static unsigned
-interpolate_alpha(long long now, long long t1, long long t2, long long t3,
-                  long long t4, unsigned a1, unsigned a2, unsigned a3)
-{
-    unsigned a;
-    double cf;
-    if (now <= t1) {
-        a = a1;
-    } else if (now >= t4) {
-        a = a3;
-    } else if (now < t2) {      // and > t1
-        cf = ((double) (now - t1)) / (t2 - t1);
-        a = a1 * (1 - cf) + a2 * cf;
-    } else if (now > t3) {
-        cf = ((double) (now - t3)) / (t4 - t3);
-        a = a2 * (1 - cf) + a3 * cf;
-    } else {                    // t2 <= now <= t3
-        a = a2;
-    }
-
-    return a;
-}
-
-/**
- * Parse a vector clip into an outline, using the proper scaling
- * parameters.  Translate it to correct for screen borders, if needed.
- */
-static char *parse_vector_clip(ASS_Renderer *render_priv, char *p)
-{
-    int scale = 1;
-    int res = 0;
-    ASS_Drawing *drawing = render_priv->state.clip_drawing;
-
-    if (drawing && drawing->glyph)
-        FT_Done_Glyph((FT_Glyph) drawing->glyph);
-    ass_drawing_free(drawing);
-    render_priv->state.clip_drawing = ass_drawing_new(
-        render_priv->fontconfig_priv,
-        render_priv->state.font,
-        render_priv->ftlibrary);
-    drawing = render_priv->state.clip_drawing;
-    skipopt('(');
-    res = mystrtoi(&p, &scale);
-    skipopt(',')
-    if (!res)
-        scale = 1;
-    drawing->scale = scale;
-    drawing->scale_x = render_priv->font_scale_x * render_priv->font_scale;
-    drawing->scale_y = render_priv->font_scale;
-    while (*p != ')' && *p != '}' && p != 0)
-        ass_drawing_add_char(drawing, *p++);
-    skipopt(')');
-
-    return p;
-}
-
-/**
- * \brief Parse style override tag.
- * \param p string to parse
- * \param pwr multiplier for some tag effects (comes from \t tags)
- */
-static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
-{
-    skip_to('\\');
-    skip('\\');
-    if ((*p == '}') || (*p == 0))
-        return p;
-
-    // New tags introduced in vsfilter 2.39
-    if (mystrcmp(&p, "xbord")) {
-        double val;
-        if (mystrtod(&p, &val))
-            val = render_priv->state.border_x * (1 - pwr) + val * pwr;
-        else
-            val = -1.;
-        change_border(render_priv, val, render_priv->state.border_y);
-    } else if (mystrcmp(&p, "ybord")) {
-        double val;
-        if (mystrtod(&p, &val))
-            val = render_priv->state.border_y * (1 - pwr) + val * pwr;
-        else
-            val = -1.;
-        change_border(render_priv, render_priv->state.border_x, val);
-    } else if (mystrcmp(&p, "xshad")) {
-        double val;
-        if (mystrtod(&p, &val))
-            val = render_priv->state.shadow_x * (1 - pwr) + val * pwr;
-        else
-            val = 0.;
-        render_priv->state.shadow_x = val;
-    } else if (mystrcmp(&p, "yshad")) {
-        double val;
-        if (mystrtod(&p, &val))
-            val = render_priv->state.shadow_y * (1 - pwr) + val * pwr;
-        else
-            val = 0.;
-        render_priv->state.shadow_y = val;
-    } else if (mystrcmp(&p, "fax")) {
-        double val;
-        if (mystrtod(&p, &val))
-            render_priv->state.fax =
-                val * pwr + render_priv->state.fax * (1 - pwr);
-        else
-            render_priv->state.fax = 0.;
-    } else if (mystrcmp(&p, "fay")) {
-        double val;
-        if (mystrtod(&p, &val))
-            render_priv->state.fay =
-                val * pwr + render_priv->state.fay * (1 - pwr);
-        else
-            render_priv->state.fay = 0.;
-    } else if (mystrcmp(&p, "iclip")) {
-        int x0, y0, x1, y1;
-        int res = 1;
-        char *start = p;
-        skipopt('(');
-        res &= mystrtoi(&p, &x0);
-        skipopt(',');
-        res &= mystrtoi(&p, &y0);
-        skipopt(',');
-        res &= mystrtoi(&p, &x1);
-        skipopt(',');
-        res &= mystrtoi(&p, &y1);
-        skipopt(')');
-        if (res) {
-            render_priv->state.clip_x0 =
-                render_priv->state.clip_x0 * (1 - pwr) + x0 * pwr;
-            render_priv->state.clip_x1 =
-                render_priv->state.clip_x1 * (1 - pwr) + x1 * pwr;
-            render_priv->state.clip_y0 =
-                render_priv->state.clip_y0 * (1 - pwr) + y0 * pwr;
-            render_priv->state.clip_y1 =
-                render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr;
-            render_priv->state.clip_mode = 1;
-        } else if (!render_priv->state.clip_drawing) {
-            p = parse_vector_clip(render_priv, start);
-            render_priv->state.clip_drawing_mode = 1;
-        } else
-            render_priv->state.clip_mode = 0;
-    } else if (mystrcmp(&p, "blur")) {
-        double val;
-        if (mystrtod(&p, &val)) {
-            val = render_priv->state.blur * (1 - pwr) + val * pwr;
-            val = (val < 0) ? 0 : val;
-            val = (val > BLUR_MAX_RADIUS) ? BLUR_MAX_RADIUS : val;
-            render_priv->state.blur = val;
-        } else
-            render_priv->state.blur = 0.0;
-        // ASS standard tags
-    } else if (mystrcmp(&p, "fsc")) {
-        char tp = *p++;
-        double val;
-        if (tp == 'x') {
-            if (mystrtod(&p, &val)) {
-                val /= 100;
-                render_priv->state.scale_x =
-                    render_priv->state.scale_x * (1 - pwr) + val * pwr;
-            } else
-                render_priv->state.scale_x =
-                    render_priv->state.style->ScaleX;
-        } else if (tp == 'y') {
-            if (mystrtod(&p, &val)) {
-                val /= 100;
-                render_priv->state.scale_y =
-                    render_priv->state.scale_y * (1 - pwr) + val * pwr;
-            } else
-                render_priv->state.scale_y =
-                    render_priv->state.style->ScaleY;
-        }
-    } else if (mystrcmp(&p, "fsp")) {
-        double val;
-        if (mystrtod(&p, &val))
-            render_priv->state.hspacing =
-                render_priv->state.hspacing * (1 - pwr) + val * pwr;
-        else
-            render_priv->state.hspacing = render_priv->state.style->Spacing;
-    } else if (mystrcmp(&p, "fs+")) {
-        double val;
-        if (mystrtod(&p, &val)) {
-            val = render_priv->state.font_size + pwr * val;
-        } else
-            val = render_priv->state.style->FontSize;
-        if (render_priv->state.font)
-            change_font_size(render_priv, val);
-    } else if (mystrcmp(&p, "fs-")) {
-        double val;
-        if (mystrtod(&p, &val))
-            val = render_priv->state.font_size - pwr * val;
-        else
-            val = render_priv->state.style->FontSize;
-        if (render_priv->state.font)
-            change_font_size(render_priv, val);
-    } else if (mystrcmp(&p, "fs")) {
-        double val;
-        if (mystrtod(&p, &val))
-            val = render_priv->state.font_size * (1 - pwr) + val * pwr;
-        else
-            val = render_priv->state.style->FontSize;
-        if (render_priv->state.font)
-            change_font_size(render_priv, val);
-    } else if (mystrcmp(&p, "bord")) {
-        double val;
-        if (mystrtod(&p, &val)) {
-            if (render_priv->state.border_x == render_priv->state.border_y)
-                val = render_priv->state.border_x * (1 - pwr) + val * pwr;
-        } else
-            val = -1.;          // reset to default
-        change_border(render_priv, val, val);
-    } else if (mystrcmp(&p, "move")) {
-        double x1, x2, y1, y2;
-        long long t1, t2, delta_t, t;
-        double x, y;
-        double k;
-        skip('(');
-        mystrtod(&p, &x1);
-        skip(',');
-        mystrtod(&p, &y1);
-        skip(',');
-        mystrtod(&p, &x2);
-        skip(',');
-        mystrtod(&p, &y2);
-        if (*p == ',') {
-            skip(',');
-            mystrtoll(&p, &t1);
-            skip(',');
-            mystrtoll(&p, &t2);
-            ass_msg(render_priv->library, MSGL_DBG2,
-                   "movement6: (%f, %f) -> (%f, %f), (%" PRId64 " .. %"
-                   PRId64 ")\n", x1, y1, x2, y2, (int64_t) t1,
-                   (int64_t) t2);
-        } else {
-            t1 = 0;
-            t2 = render_priv->state.event->Duration;
-            ass_msg(render_priv->library, MSGL_DBG2,
-                   "movement: (%f, %f) -> (%f, %f)", x1, y1, x2, y2);
-        }
-        skip(')');
-        delta_t = t2 - t1;
-        t = render_priv->time - render_priv->state.event->Start;
-        if (t < t1)
-            k = 0.;
-        else if (t > t2)
-            k = 1.;
-        else
-            k = ((double) (t - t1)) / delta_t;
-        x = k * (x2 - x1) + x1;
-        y = k * (y2 - y1) + y1;
-        if (render_priv->state.evt_type != EVENT_POSITIONED) {
-            render_priv->state.pos_x = x;
-            render_priv->state.pos_y = y;
-            render_priv->state.detect_collisions = 0;
-            render_priv->state.evt_type = EVENT_POSITIONED;
-        }
-    } else if (mystrcmp(&p, "frx")) {
-        double val;
-        if (mystrtod(&p, &val)) {
-            val *= M_PI / 180;
-            render_priv->state.frx =
-                val * pwr + render_priv->state.frx * (1 - pwr);
-        } else
-            render_priv->state.frx = 0.;
-    } else if (mystrcmp(&p, "fry")) {
-        double val;
-        if (mystrtod(&p, &val)) {
-            val *= M_PI / 180;
-            render_priv->state.fry =
-                val * pwr + render_priv->state.fry * (1 - pwr);
-        } else
-            render_priv->state.fry = 0.;
-    } else if (mystrcmp(&p, "frz") || mystrcmp(&p, "fr")) {
-        double val;
-        if (mystrtod(&p, &val)) {
-            val *= M_PI / 180;
-            render_priv->state.frz =
-                val * pwr + render_priv->state.frz * (1 - pwr);
-        } else
-            render_priv->state.frz =
-                M_PI * render_priv->state.style->Angle / 180.;
-    } else if (mystrcmp(&p, "fn")) {
-        char *start = p;
-        char *family;
-        skip_to('\\');
-        if (p > start) {
-            family = malloc(p - start + 1);
-            strncpy(family, start, p - start);
-            family[p - start] = '\0';
-        } else
-            family = strdup(render_priv->state.style->FontName);
-        free(render_priv->state.family);
-        render_priv->state.family = family;
-        update_font(render_priv);
-    } else if (mystrcmp(&p, "alpha")) {
-        uint32_t val;
-        int i;
-        int hex = render_priv->track->track_type == TRACK_TYPE_ASS;
-        if (strtocolor(render_priv->library, &p, &val, hex)) {
-            unsigned char a = val >> 24;
-            for (i = 0; i < 4; ++i)
-                change_alpha(&render_priv->state.c[i], a, pwr);
-        } else {
-            change_alpha(&render_priv->state.c[0],
-                         render_priv->state.style->PrimaryColour, pwr);
-            change_alpha(&render_priv->state.c[1],
-                         render_priv->state.style->SecondaryColour, pwr);
-            change_alpha(&render_priv->state.c[2],
-                         render_priv->state.style->OutlineColour, pwr);
-            change_alpha(&render_priv->state.c[3],
-                         render_priv->state.style->BackColour, pwr);
-        }
-        // FIXME: simplify
-    } else if (mystrcmp(&p, "an")) {
-        int val;
-        if (mystrtoi(&p, &val) && val) {
-            int v = (val - 1) / 3;      // 0, 1 or 2 for vertical alignment
-            ass_msg(render_priv->library, MSGL_DBG2, "an %d", val);
-            if (v != 0)
-                v = 3 - v;
-            val = ((val - 1) % 3) + 1;  // horizontal alignment
-            val += v * 4;
-            ass_msg(render_priv->library, MSGL_DBG2, "align %d", val);
-            render_priv->state.alignment = val;
-        } else
-            render_priv->state.alignment =
-                render_priv->state.style->Alignment;
-    } else if (mystrcmp(&p, "a")) {
-        int val;
-        if (mystrtoi(&p, &val) && val)
-            // take care of a vsfilter quirk: handle illegal \a8 like \a5
-            render_priv->state.alignment = (val == 8) ? 5 : val;
-        else
-            render_priv->state.alignment =
-                render_priv->state.style->Alignment;
-    } else if (mystrcmp(&p, "pos")) {
-        double v1, v2;
-        skip('(');
-        mystrtod(&p, &v1);
-        skip(',');
-        mystrtod(&p, &v2);
-        skip(')');
-        ass_msg(render_priv->library, MSGL_DBG2, "pos(%f, %f)", v1, v2);
-        if (render_priv->state.evt_type == EVENT_POSITIONED) {
-            ass_msg(render_priv->library, MSGL_V, "Subtitle has a new \\pos "
-                   "after \\move or \\pos, ignoring");
-        } else {
-            render_priv->state.evt_type = EVENT_POSITIONED;
-            render_priv->state.detect_collisions = 0;
-            render_priv->state.pos_x = v1;
-            render_priv->state.pos_y = v2;
-        }
-    } else if (mystrcmp(&p, "fad")) {
-        int a1, a2, a3;
-        long long t1, t2, t3, t4;
-        if (*p == 'e')
-            ++p;                // either \fad or \fade
-        skip('(');
-        mystrtoi(&p, &a1);
-        skip(',');
-        mystrtoi(&p, &a2);
-        if (*p == ')') {
-            // 2-argument version (\fad, according to specs)
-            // a1 and a2 are fade-in and fade-out durations
-            t1 = 0;
-            t4 = render_priv->state.event->Duration;
-            t2 = a1;
-            t3 = t4 - a2;
-            a1 = 0xFF;
-            a2 = 0;
-            a3 = 0xFF;
-        } else {
-            // 6-argument version (\fade)
-            // a1 and a2 (and a3) are opacity values
-            skip(',');
-            mystrtoi(&p, &a3);
-            skip(',');
-            mystrtoll(&p, &t1);
-            skip(',');
-            mystrtoll(&p, &t2);
-            skip(',');
-            mystrtoll(&p, &t3);
-            skip(',');
-            mystrtoll(&p, &t4);
-        }
-        skip(')');
-        render_priv->state.fade =
-            interpolate_alpha(render_priv->time -
-                              render_priv->state.event->Start, t1, t2,
-                              t3, t4, a1, a2, a3);
-    } else if (mystrcmp(&p, "org")) {
-        int v1, v2;
-        skip('(');
-        mystrtoi(&p, &v1);
-        skip(',');
-        mystrtoi(&p, &v2);
-        skip(')');
-        ass_msg(render_priv->library, MSGL_DBG2, "org(%d, %d)", v1, v2);
-        if (!render_priv->state.have_origin) {
-            render_priv->state.org_x = v1;
-            render_priv->state.org_y = v2;
-            render_priv->state.have_origin = 1;
-            render_priv->state.detect_collisions = 0;
-        }
-    } else if (mystrcmp(&p, "t")) {
-        double v[3];
-        int v1, v2;
-        double v3;
-        int cnt;
-        long long t1, t2, t, delta_t;
-        double k;
-        skip('(');
-        for (cnt = 0; cnt < 3; ++cnt) {
-            if (*p == '\\')
-                break;
-            mystrtod(&p, &v[cnt]);
-            skip(',');
-        }
-        if (cnt == 3) {
-            v1 = v[0];
-            v2 = (v[1] < v1) ? render_priv->state.event->Duration : v[1];
-            v3 = v[2];
-        } else if (cnt == 2) {
-            v1 = v[0];
-            v2 = (v[1] < v1) ? render_priv->state.event->Duration : v[1];
-            v3 = 1.;
-        } else if (cnt == 1) {
-            v1 = 0;
-            v2 = render_priv->state.event->Duration;
-            v3 = v[0];
-        } else {                // cnt == 0
-            v1 = 0;
-            v2 = render_priv->state.event->Duration;
-            v3 = 1.;
-        }
-        render_priv->state.detect_collisions = 0;
-        t1 = v1;
-        t2 = v2;
-        delta_t = v2 - v1;
-        if (v3 < 0.)
-            v3 = 0.;
-        t = render_priv->time - render_priv->state.event->Start;        // FIXME: move to render_context
-        if (t <= t1)
-            k = 0.;
-        else if (t >= t2)
-            k = 1.;
-        else {
-            assert(delta_t != 0.);
-            k = pow(((double) (t - t1)) / delta_t, v3);
-        }
-        while (*p == '\\')
-            p = parse_tag(render_priv, p, k);   // maybe k*pwr ? no, specs forbid nested \t's
-        skip_to(')');           // in case there is some unknown tag or a comment
-        skip(')');
-    } else if (mystrcmp(&p, "clip")) {
-        char *start = p;
-        int x0, y0, x1, y1;
-        int res = 1;
-        skipopt('(');
-        res &= mystrtoi(&p, &x0);
-        skipopt(',');
-        res &= mystrtoi(&p, &y0);
-        skipopt(',');
-        res &= mystrtoi(&p, &x1);
-        skipopt(',');
-        res &= mystrtoi(&p, &y1);
-        skipopt(')');
-        if (res) {
-            render_priv->state.clip_x0 =
-                render_priv->state.clip_x0 * (1 - pwr) + x0 * pwr;
-            render_priv->state.clip_x1 =
-                render_priv->state.clip_x1 * (1 - pwr) + x1 * pwr;
-            render_priv->state.clip_y0 =
-                render_priv->state.clip_y0 * (1 - pwr) + y0 * pwr;
-            render_priv->state.clip_y1 =
-                render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr;
-        // Might be a vector clip
-        } else if (!render_priv->state.clip_drawing) {
-            p = parse_vector_clip(render_priv, start);
-            render_priv->state.clip_drawing_mode = 0;
-        } else {
-            render_priv->state.clip_x0 = 0;
-            render_priv->state.clip_y0 = 0;
-            render_priv->state.clip_x1 = render_priv->track->PlayResX;
-            render_priv->state.clip_y1 = render_priv->track->PlayResY;
-        }
-    } else if (mystrcmp(&p, "c")) {
-        uint32_t val;
-        int hex = render_priv->track->track_type == TRACK_TYPE_ASS;
-        if (!strtocolor(render_priv->library, &p, &val, hex))
-            val = render_priv->state.style->PrimaryColour;
-        ass_msg(render_priv->library, MSGL_DBG2, "color: %X", val);
-        change_color(&render_priv->state.c[0], val, pwr);
-    } else if ((*p >= '1') && (*p <= '4') && (++p)
-               && (mystrcmp(&p, "c") || mystrcmp(&p, "a"))) {
-        char n = *(p - 2);
-        int cidx = n - '1';
-        char cmd = *(p - 1);
-        uint32_t val;
-        int hex = render_priv->track->track_type == TRACK_TYPE_ASS;
-        assert((n >= '1') && (n <= '4'));
-        if (!strtocolor(render_priv->library, &p, &val, hex))
-            switch (n) {
-            case '1':
-                val = render_priv->state.style->PrimaryColour;
-                break;
-            case '2':
-                val = render_priv->state.style->SecondaryColour;
-                break;
-            case '3':
-                val = render_priv->state.style->OutlineColour;
-                break;
-            case '4':
-                val = render_priv->state.style->BackColour;
-                break;
-            default:
-                val = 0;
-                break;          // impossible due to assert; avoid compilation warning
-            }
-        switch (cmd) {
-        case 'c':
-            change_color(render_priv->state.c + cidx, val, pwr);
-            break;
-        case 'a':
-            change_alpha(render_priv->state.c + cidx, val >> 24, pwr);
-            break;
-        default:
-            ass_msg(render_priv->library, MSGL_WARN, "Bad command: %c%c",
-                    n, cmd);
-            break;
-        }
-        ass_msg(render_priv->library, MSGL_DBG2, "single c/a at %f: %c%c = %X",
-               pwr, n, cmd, render_priv->state.c[cidx]);
-    } else if (mystrcmp(&p, "r")) {
-        reset_render_context(render_priv);
-    } else if (mystrcmp(&p, "be")) {
-        int val;
-        if (mystrtoi(&p, &val)) {
-            // Clamp to a safe upper limit, since high values need excessive CPU
-            val = (val < 0) ? 0 : val;
-            val = (val > MAX_BE) ? MAX_BE : val;
-            render_priv->state.be = val;
-        } else
-            render_priv->state.be = 0;
-    } else if (mystrcmp(&p, "b")) {
-        int b;
-        if (mystrtoi(&p, &b)) {
-            if (pwr >= .5)
-                render_priv->state.bold = b;
-        } else
-            render_priv->state.bold = render_priv->state.style->Bold;
-        update_font(render_priv);
-    } else if (mystrcmp(&p, "i")) {
-        int i;
-        if (mystrtoi(&p, &i)) {
-            if (pwr >= .5)
-                render_priv->state.italic = i;
-        } else
-            render_priv->state.italic = render_priv->state.style->Italic;
-        update_font(render_priv);
-    } else if (mystrcmp(&p, "kf") || mystrcmp(&p, "K")) {
-        int val = 0;
-        mystrtoi(&p, &val);
-        render_priv->state.effect_type = EF_KARAOKE_KF;
-        if (render_priv->state.effect_timing)
-            render_priv->state.effect_skip_timing +=
-                render_priv->state.effect_timing;
-        render_priv->state.effect_timing = val * 10;
-    } else if (mystrcmp(&p, "ko")) {
-        int val = 0;
-        mystrtoi(&p, &val);
-        render_priv->state.effect_type = EF_KARAOKE_KO;
-        if (render_priv->state.effect_timing)
-            render_priv->state.effect_skip_timing +=
-                render_priv->state.effect_timing;
-        render_priv->state.effect_timing = val * 10;
-    } else if (mystrcmp(&p, "k")) {
-        int val = 0;
-        mystrtoi(&p, &val);
-        render_priv->state.effect_type = EF_KARAOKE;
-        if (render_priv->state.effect_timing)
-            render_priv->state.effect_skip_timing +=
-                render_priv->state.effect_timing;
-        render_priv->state.effect_timing = val * 10;
-    } else if (mystrcmp(&p, "shad")) {
-        double val;
-        if (mystrtod(&p, &val)) {
-            if (render_priv->state.shadow_x == render_priv->state.shadow_y)
-                val = render_priv->state.shadow_x * (1 - pwr) + val * pwr;
-        } else
-            val = 0.;
-        render_priv->state.shadow_x = render_priv->state.shadow_y = val;
-    } else if (mystrcmp(&p, "s")) {
-        int val;
-        if (mystrtoi(&p, &val) && val)
-            render_priv->state.flags |= DECO_STRIKETHROUGH;
-        else
-            render_priv->state.flags &= ~DECO_STRIKETHROUGH;
-    } else if (mystrcmp(&p, "u")) {
-        int val;
-        if (mystrtoi(&p, &val) && val)
-            render_priv->state.flags |= DECO_UNDERLINE;
-        else
-            render_priv->state.flags &= ~DECO_UNDERLINE;
-    } else if (mystrcmp(&p, "pbo")) {
-        double val = 0;
-        if (mystrtod(&p, &val))
-            render_priv->state.drawing->pbo = val;
-    } else if (mystrcmp(&p, "p")) {
-        int val;
-        if (!mystrtoi(&p, &val))
-            val = 0;
-        if (val)
-            render_priv->state.drawing->scale = val;
-        render_priv->state.drawing_mode = !!val;
-    } else if (mystrcmp(&p, "q")) {
-        int val;
-        if (!mystrtoi(&p, &val))
-            val = render_priv->track->WrapStyle;
-        render_priv->state.wrap_style = val;
-    }
-
-    return p;
-}
-
-void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event)
-{
-    int v[4];
-    int cnt;
-    char *p = event->Effect;
-
-    if (!p || !*p)
-        return;
-
-    cnt = 0;
-    while (cnt < 4 && (p = strchr(p, ';'))) {
-        v[cnt++] = atoi(++p);
-    }
-
-    if (strncmp(event->Effect, "Banner;", 7) == 0) {
-        int delay;
-        if (cnt < 1) {
-            ass_msg(render_priv->library, MSGL_V,
-                    "Error parsing effect: '%s'", event->Effect);
-            return;
-        }
-        if (cnt >= 2 && v[1] == 0)      // right-to-left
-            render_priv->state.scroll_direction = SCROLL_RL;
-        else                    // left-to-right
-            render_priv->state.scroll_direction = SCROLL_LR;
-
-        delay = v[0];
-        if (delay == 0)
-            delay = 1;          // ?
-        render_priv->state.scroll_shift =
-            (render_priv->time - render_priv->state.event->Start) / delay;
-        render_priv->state.evt_type = EVENT_HSCROLL;
-        return;
-    }
-
-    if (strncmp(event->Effect, "Scroll up;", 10) == 0) {
-        render_priv->state.scroll_direction = SCROLL_BT;
-    } else if (strncmp(event->Effect, "Scroll down;", 12) == 0) {
-        render_priv->state.scroll_direction = SCROLL_TB;
-    } else {
-        ass_msg(render_priv->library, MSGL_DBG2,
-                "Unknown transition effect: '%s'", event->Effect);
-        return;
-    }
-    // parse scroll up/down parameters
-    {
-        int delay;
-        int y0, y1;
-        if (cnt < 3) {
-            ass_msg(render_priv->library, MSGL_V,
-                    "Error parsing effect: '%s'", event->Effect);
-            return;
-        }
-        delay = v[2];
-        if (delay == 0)
-            delay = 1;          // ?
-        render_priv->state.scroll_shift =
-            (render_priv->time - render_priv->state.event->Start) / delay;
-        if (v[0] < v[1]) {
-            y0 = v[0];
-            y1 = v[1];
-        } else {
-            y0 = v[1];
-            y1 = v[0];
-        }
-        if (y1 == 0)
-            y1 = render_priv->track->PlayResY;  // y0=y1=0 means fullscreen scrolling
-        render_priv->state.clip_y0 = y0;
-        render_priv->state.clip_y1 = y1;
-        render_priv->state.evt_type = EVENT_VSCROLL;
-        render_priv->state.detect_collisions = 0;
-    }
-
-}
-
-/**
- * \brief Get next ucs4 char from string, parsing and executing style overrides
- * \param str string pointer
- * \return ucs4 code of the next char
- * On return str points to the unparsed part of the string
- */
-unsigned get_next_char(ASS_Renderer *render_priv, char **str)
-{
-    char *p = *str;
-    unsigned chr;
-    if (*p == '{') {            // '\0' goes here
-        p++;
-        while (1) {
-            p = parse_tag(render_priv, p, 1.);
-            if (*p == '}') {    // end of tag
-                p++;
-                if (*p == '{') {
-                    p++;
-                    continue;
-                } else
-                    break;
-            } else if (*p != '\\')
-                ass_msg(render_priv->library, MSGL_V,
-                        "Unable to parse: '%.30s'", p);
-            if (*p == 0)
-                break;
-        }
-    }
-    if (*p == '\t') {
-        ++p;
-        *str = p;
-        return ' ';
-    }
-    if (*p == '\\') {
-        if ((p[1] == 'N') || ((p[1] == 'n') &&
-                              (render_priv->state.wrap_style == 2))) {
-            p += 2;
-            *str = p;
-            return '\n';
-        } else if (p[1] == 'n') {
-            p += 2;
-            *str = p;
-            return ' ';
-        } else if (p[1] == 'h') {
-            p += 2;
-            *str = p;
-            return NBSP;
-        } else if (p[1] == '{') {
-            p += 2;
-            *str = p;
-            return '{';
-        } else if (p[1] == '}') {
-            p += 2;
-            *str = p;
-            return '}';
-        }
-    }
-    chr = ass_utf8_get_char((char **) &p);
-    *str = p;
-    return chr;
-}
diff --git a/aegisub/libass/ass_parse.h b/aegisub/libass/ass_parse.h
deleted file mode 100644
index c65b56515..000000000
--- a/aegisub/libass/ass_parse.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef LIBASS_PARSE_H
-#define LIBASS_PARSE_H
-
-#define BLUR_MAX_RADIUS 100.0
-
-#define _r(c)   ((c) >> 24)
-#define _g(c)   (((c) >> 16) & 0xFF)
-#define _b(c)   (((c) >> 8) & 0xFF)
-#define _a(c)   ((c) & 0xFF)
-
-void update_font(ASS_Renderer *render_priv);
-void change_border(ASS_Renderer *render_priv, double border_x,
-                   double border_y);
-void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event);
-unsigned get_next_char(ASS_Renderer *render_priv, char **str);
-extern void change_alpha(uint32_t *var, uint32_t new, double pwr);
-extern uint32_t mult_alpha(uint32_t a, uint32_t b);
-
-
-#endif /* LIBASS_PARSE_H */
diff --git a/aegisub/libass/ass_render.c b/aegisub/libass/ass_render.c
deleted file mode 100644
index 21170667a..000000000
--- a/aegisub/libass/ass_render.c
+++ /dev/null
@@ -1,2538 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <math.h>
-
-#include "ass_render.h"
-#include "ass_parse.h"
-
-#define MAX_GLYPHS_INITIAL 1024
-#define MAX_LINES_INITIAL 64
-#define SUBPIXEL_MASK 63
-#define SUBPIXEL_ACCURACY 7
-
-static void ass_lazy_track_init(ASS_Renderer *render_priv)
-{
-    ASS_Track *track = render_priv->track;
-
-    if (track->PlayResX && track->PlayResY)
-        return;
-    if (!track->PlayResX && !track->PlayResY) {
-        ass_msg(render_priv->library, MSGL_WARN,
-               "Neither PlayResX nor PlayResY defined. Assuming 384x288");
-        track->PlayResX = 384;
-        track->PlayResY = 288;
-    } else {
-        if (!track->PlayResY && track->PlayResX == 1280) {
-            track->PlayResY = 1024;
-            ass_msg(render_priv->library, MSGL_WARN,
-                   "PlayResY undefined, setting to %d", track->PlayResY);
-        } else if (!track->PlayResY) {
-            track->PlayResY = track->PlayResX * 3 / 4;
-            ass_msg(render_priv->library, MSGL_WARN,
-                   "PlayResY undefined, setting to %d", track->PlayResY);
-        } else if (!track->PlayResX && track->PlayResY == 1024) {
-            track->PlayResX = 1280;
-            ass_msg(render_priv->library, MSGL_WARN,
-                   "PlayResX undefined, setting to %d", track->PlayResX);
-        } else if (!track->PlayResX) {
-            track->PlayResX = track->PlayResY * 4 / 3;
-            ass_msg(render_priv->library, MSGL_WARN,
-                   "PlayResX undefined, setting to %d", track->PlayResX);
-        }
-    }
-}
-
-ASS_Renderer *ass_renderer_init(ASS_Library *library)
-{
-    int error;
-    FT_Library ft;
-    ASS_Renderer *priv = 0;
-    int vmajor, vminor, vpatch;
-
-    error = FT_Init_FreeType(&ft);
-    if (error) {
-        ass_msg(library, MSGL_FATAL, "%s failed", "FT_Init_FreeType");
-        goto ass_init_exit;
-    }
-
-    FT_Library_Version(ft, &vmajor, &vminor, &vpatch);
-    ass_msg(library, MSGL_V, "FreeType library version: %d.%d.%d",
-           vmajor, vminor, vpatch);
-    ass_msg(library, MSGL_V, "FreeType headers version: %d.%d.%d",
-           FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
-
-    priv = calloc(1, sizeof(ASS_Renderer));
-    if (!priv) {
-        FT_Done_FreeType(ft);
-        goto ass_init_exit;
-    }
-
-    priv->synth_priv = ass_synth_init(BLUR_MAX_RADIUS);
-
-    priv->library = library;
-    priv->ftlibrary = ft;
-    // images_root and related stuff is zero-filled in calloc
-
-    priv->cache.font_cache = ass_font_cache_init(library);
-    priv->cache.bitmap_cache = ass_bitmap_cache_init(library);
-    priv->cache.composite_cache = ass_composite_cache_init(library);
-    priv->cache.glyph_cache = ass_glyph_cache_init(library);
-    priv->cache.glyph_max = GLYPH_CACHE_MAX;
-    priv->cache.bitmap_max_size = BITMAP_CACHE_MAX_SIZE;
-
-    priv->text_info.max_glyphs = MAX_GLYPHS_INITIAL;
-    priv->text_info.max_lines = MAX_LINES_INITIAL;
-    priv->text_info.glyphs = calloc(MAX_GLYPHS_INITIAL, sizeof(GlyphInfo));
-    priv->text_info.lines = calloc(MAX_LINES_INITIAL, sizeof(LineInfo));
-
-    priv->settings.font_size_coeff = 1.;
-
-  ass_init_exit:
-    if (priv)
-        ass_msg(library, MSGL_V, "Init");
-    else
-        ass_msg(library, MSGL_ERR, "Init failed");
-
-    return priv;
-}
-
-static void free_list_clear(ASS_Renderer *render_priv)
-{
-    if (render_priv->free_head) {
-        FreeList *item = render_priv->free_head;
-        while(item) {
-            FreeList *oi = item;
-            free(item->object);
-            item = item->next;
-            free(oi);
-        }
-        render_priv->free_head = NULL;
-    }
-}
-
-void ass_renderer_done(ASS_Renderer *render_priv)
-{
-    ass_font_cache_done(render_priv->cache.font_cache);
-    ass_bitmap_cache_done(render_priv->cache.bitmap_cache);
-    ass_composite_cache_done(render_priv->cache.composite_cache);
-    ass_glyph_cache_done(render_priv->cache.glyph_cache);
-
-    ass_free_images(render_priv->images_root);
-    ass_free_images(render_priv->prev_images_root);
-
-    if (render_priv->state.stroker) {
-        FT_Stroker_Done(render_priv->state.stroker);
-        render_priv->state.stroker = 0;
-    }
-    if (render_priv->ftlibrary)
-        FT_Done_FreeType(render_priv->ftlibrary);
-    if (render_priv->fontconfig_priv)
-        fontconfig_done(render_priv->fontconfig_priv);
-    if (render_priv->synth_priv)
-        ass_synth_done(render_priv->synth_priv);
-    free(render_priv->eimg);
-    free(render_priv->text_info.glyphs);
-    free(render_priv->text_info.lines);
-
-    free(render_priv->settings.default_font);
-    free(render_priv->settings.default_family);
-
-    free_list_clear(render_priv);
-    free(render_priv);
-}
-
-/**
- * \brief Create a new ASS_Image
- * Parameters are the same as ASS_Image fields.
- */
-static ASS_Image *my_draw_bitmap(unsigned char *bitmap, int bitmap_w,
-                                 int bitmap_h, int stride, int dst_x,
-                                 int dst_y, uint32_t color)
-{
-    ASS_Image *img = malloc(sizeof(ASS_Image));
-
-    if (img) {
-        img->w = bitmap_w;
-        img->h = bitmap_h;
-        img->stride = stride;
-        img->bitmap = bitmap;
-        img->color = color;
-        img->dst_x = dst_x;
-        img->dst_y = dst_y;
-    }
-
-    return img;
-}
-
-/**
- * \brief Mapping between script and screen coordinates
- */
-static double x2scr(ASS_Renderer *render_priv, double x)
-{
-    return x * render_priv->orig_width_nocrop / render_priv->font_scale_x /
-        render_priv->track->PlayResX +
-        FFMAX(render_priv->settings.left_margin, 0);
-}
-static double x2scr_pos(ASS_Renderer *render_priv, double x)
-{
-    return x * render_priv->orig_width / render_priv->font_scale_x / render_priv->track->PlayResX +
-        render_priv->settings.left_margin;
-}
-static double x2scr_scaled(ASS_Renderer *render_priv, double x)
-{
-    return x * render_priv->orig_width_nocrop /
-        render_priv->track->PlayResX +
-        FFMAX(render_priv->settings.left_margin, 0);
-}
-static double x2scr_pos_scaled(ASS_Renderer *render_priv, double x)
-{
-    return x * render_priv->orig_width / render_priv->track->PlayResX +
-        render_priv->settings.left_margin;
-}
-/**
- * \brief Mapping between script and screen coordinates
- */
-static double y2scr(ASS_Renderer *render_priv, double y)
-{
-    return y * render_priv->orig_height_nocrop /
-        render_priv->track->PlayResY +
-        FFMAX(render_priv->settings.top_margin, 0);
-}
-static double y2scr_pos(ASS_Renderer *render_priv, double y)
-{
-    return y * render_priv->orig_height / render_priv->track->PlayResY +
-        render_priv->settings.top_margin;
-}
-
-// the same for toptitles
-static double y2scr_top(ASS_Renderer *render_priv, double y)
-{
-    if (render_priv->settings.use_margins)
-        return y * render_priv->orig_height_nocrop /
-            render_priv->track->PlayResY;
-    else
-        return y * render_priv->orig_height_nocrop /
-            render_priv->track->PlayResY +
-            FFMAX(render_priv->settings.top_margin, 0);
-}
-// the same for subtitles
-static double y2scr_sub(ASS_Renderer *render_priv, double y)
-{
-    if (render_priv->settings.use_margins)
-        return y * render_priv->orig_height_nocrop /
-            render_priv->track->PlayResY +
-            FFMAX(render_priv->settings.top_margin, 0)
-            + FFMAX(render_priv->settings.bottom_margin, 0);
-    else
-        return y * render_priv->orig_height_nocrop /
-            render_priv->track->PlayResY +
-            FFMAX(render_priv->settings.top_margin, 0);
-}
-
-/*
- * \brief Convert bitmap glyphs into ASS_Image list with inverse clipping
- *
- * Inverse clipping with the following strategy:
- * - find rectangle from (x0, y0) to (cx0, y1)
- * - find rectangle from (cx0, y0) to (cx1, cy0)
- * - find rectangle from (cx0, cy1) to (cx1, y1)
- * - find rectangle from (cx1, y0) to (x1, y1)
- * These rectangles can be invalid and in this case are discarded.
- * Afterwards, they are clipped against the screen coordinates.
- * In an additional pass, the rectangles need to be split up left/right for
- * karaoke effects.  This can result in a lot of bitmaps (6 to be exact).
- */
-static ASS_Image **render_glyph_i(ASS_Renderer *render_priv,
-                                  Bitmap *bm, int dst_x, int dst_y,
-                                  uint32_t color, uint32_t color2, int brk,
-                                  ASS_Image **tail)
-{
-    int i, j, x0, y0, x1, y1, cx0, cy0, cx1, cy1, sx, sy, zx, zy;
-    Rect r[4];
-    ASS_Image *img;
-
-    dst_x += bm->left;
-    dst_y += bm->top;
-
-    // we still need to clip against screen boundaries
-    zx = x2scr_pos_scaled(render_priv, 0);
-    zy = y2scr_pos(render_priv, 0);
-    sx = x2scr_pos_scaled(render_priv, render_priv->track->PlayResX);
-    sy = y2scr_pos(render_priv, render_priv->track->PlayResY);
-
-    x0 = 0;
-    y0 = 0;
-    x1 = bm->w;
-    y1 = bm->h;
-    cx0 = render_priv->state.clip_x0 - dst_x;
-    cy0 = render_priv->state.clip_y0 - dst_y;
-    cx1 = render_priv->state.clip_x1 - dst_x;
-    cy1 = render_priv->state.clip_y1 - dst_y;
-
-    // calculate rectangles and discard invalid ones while we're at it.
-    i = 0;
-    r[i].x0 = x0;
-    r[i].y0 = y0;
-    r[i].x1 = (cx0 > x1) ? x1 : cx0;
-    r[i].y1 = y1;
-    if (r[i].x1 > r[i].x0 && r[i].y1 > r[i].y0) i++;
-    r[i].x0 = (cx0 < 0) ? x0 : cx0;
-    r[i].y0 = y0;
-    r[i].x1 = (cx1 > x1) ? x1 : cx1;
-    r[i].y1 = (cy0 > y1) ? y1 : cy0;
-    if (r[i].x1 > r[i].x0 && r[i].y1 > r[i].y0) i++;
-    r[i].x0 = (cx0 < 0) ? x0 : cx0;
-    r[i].y0 = (cy1 < 0) ? y0 : cy1;
-    r[i].x1 = (cx1 > x1) ? x1 : cx1;
-    r[i].y1 = y1;
-    if (r[i].x1 > r[i].x0 && r[i].y1 > r[i].y0) i++;
-    r[i].x0 = (cx1 < 0) ? x0 : cx1;
-    r[i].y0 = y0;
-    r[i].x1 = x1;
-    r[i].y1 = y1;
-    if (r[i].x1 > r[i].x0 && r[i].y1 > r[i].y0) i++;
-
-    // clip each rectangle to screen coordinates
-    for (j = 0; j < i; j++) {
-        r[j].x0 = (r[j].x0 + dst_x < zx) ? zx - dst_x : r[j].x0;
-        r[j].y0 = (r[j].y0 + dst_y < zy) ? zy - dst_y : r[j].y0;
-        r[j].x1 = (r[j].x1 + dst_x > sx) ? sx - dst_x : r[j].x1;
-        r[j].y1 = (r[j].y1 + dst_y > sy) ? sy - dst_y : r[j].y1;
-    }
-
-    // draw the rectangles
-    for (j = 0; j < i; j++) {
-        int lbrk = brk;
-        // kick out rectangles that are invalid now
-        if (r[j].x1 <= r[j].x0 || r[j].y1 <= r[j].y0)
-            continue;
-        // split up into left and right for karaoke, if needed
-        if (lbrk > r[j].x0) {
-            if (lbrk > r[j].x1) lbrk = r[j].x1;
-            img = my_draw_bitmap(bm->buffer + r[j].y0 * bm->w + r[j].x0,
-                lbrk - r[j].x0, r[j].y1 - r[j].y0,
-                bm->w, dst_x + r[j].x0, dst_y + r[j].y0, color);
-            if (!img) break;
-            *tail = img;
-            tail = &img->next;
-        }
-        if (lbrk < r[j].x1) {
-            if (lbrk < r[j].x0) lbrk = r[j].x0;
-            img = my_draw_bitmap(bm->buffer + r[j].y0 * bm->w + lbrk,
-                r[j].x1 - lbrk, r[j].y1 - r[j].y0,
-                bm->w, dst_x + lbrk, dst_y + r[j].y0, color2);
-            if (!img) break;
-            *tail = img;
-            tail = &img->next;
-        }
-    }
-
-    return tail;
-}
-
-/**
- * \brief convert bitmap glyph into ASS_Image struct(s)
- * \param bit freetype bitmap glyph, FT_PIXEL_MODE_GRAY
- * \param dst_x bitmap x coordinate in video frame
- * \param dst_y bitmap y coordinate in video frame
- * \param color first color, RGBA
- * \param color2 second color, RGBA
- * \param brk x coordinate relative to glyph origin, color is used to the left of brk, color2 - to the right
- * \param tail pointer to the last image's next field, head of the generated list should be stored here
- * \return pointer to the new list tail
- * Performs clipping. Uses my_draw_bitmap for actual bitmap convertion.
- */
-static ASS_Image **
-render_glyph(ASS_Renderer *render_priv, Bitmap *bm, int dst_x, int dst_y,
-             uint32_t color, uint32_t color2, int brk, ASS_Image **tail)
-{
-    // brk is relative to dst_x
-    // color = color left of brk
-    // color2 = color right of brk
-    int b_x0, b_y0, b_x1, b_y1; // visible part of the bitmap
-    int clip_x0, clip_y0, clip_x1, clip_y1;
-    int tmp;
-    ASS_Image *img;
-
-    // Inverse clipping in use?
-    if (render_priv->state.clip_mode)
-        return render_glyph_i(render_priv, bm, dst_x, dst_y, color, color2,
-                              brk, tail);
-
-    dst_x += bm->left;
-    dst_y += bm->top;
-    brk -= bm->left;
-
-    // clipping
-    clip_x0 = FFMINMAX(render_priv->state.clip_x0, 0, render_priv->width);
-    clip_y0 = FFMINMAX(render_priv->state.clip_y0, 0, render_priv->height);
-    clip_x1 = FFMINMAX(render_priv->state.clip_x1, 0, render_priv->width);
-    clip_y1 = FFMINMAX(render_priv->state.clip_y1, 0, render_priv->height);
-    b_x0 = 0;
-    b_y0 = 0;
-    b_x1 = bm->w;
-    b_y1 = bm->h;
-
-    tmp = dst_x - clip_x0;
-    if (tmp < 0) {
-        ass_msg(render_priv->library, MSGL_DBG2, "clip left");
-        b_x0 = -tmp;
-    }
-    tmp = dst_y - clip_y0;
-    if (tmp < 0) {
-        ass_msg(render_priv->library, MSGL_DBG2, "clip top");
-        b_y0 = -tmp;
-    }
-    tmp = clip_x1 - dst_x - bm->w;
-    if (tmp < 0) {
-        ass_msg(render_priv->library, MSGL_DBG2, "clip right");
-        b_x1 = bm->w + tmp;
-    }
-    tmp = clip_y1 - dst_y - bm->h;
-    if (tmp < 0) {
-        ass_msg(render_priv->library, MSGL_DBG2, "clip bottom");
-        b_y1 = bm->h + tmp;
-    }
-
-    if ((b_y0 >= b_y1) || (b_x0 >= b_x1))
-        return tail;
-
-    if (brk > b_x0) {           // draw left part
-        if (brk > b_x1)
-            brk = b_x1;
-        img = my_draw_bitmap(bm->buffer + bm->w * b_y0 + b_x0,
-                             brk - b_x0, b_y1 - b_y0, bm->w,
-                             dst_x + b_x0, dst_y + b_y0, color);
-        if (!img) return tail;
-        *tail = img;
-        tail = &img->next;
-    }
-    if (brk < b_x1) {           // draw right part
-        if (brk < b_x0)
-            brk = b_x0;
-        img = my_draw_bitmap(bm->buffer + bm->w * b_y0 + brk,
-                             b_x1 - brk, b_y1 - b_y0, bm->w,
-                             dst_x + brk, dst_y + b_y0, color2);
-        if (!img) return tail;
-        *tail = img;
-        tail = &img->next;
-    }
-    return tail;
-}
-
-/**
- * \brief Replace the bitmap buffer in ASS_Image with a copy
- * \param img ASS_Image to operate on
- * \return pointer to old bitmap buffer
- */
-static unsigned char *clone_bitmap_buffer(ASS_Image *img)
-{
-    unsigned char *old_bitmap = img->bitmap;
-    int size = img->stride * (img->h - 1) + img->w;
-    img->bitmap = malloc(size);
-    memcpy(img->bitmap, old_bitmap, size);
-    return old_bitmap;
-}
-
-/**
- * \brief Calculate overlapping area of two consecutive bitmaps and in case they
- * overlap, blend them together
- * Mainly useful for translucent glyphs and especially borders, to avoid the
- * luminance adding up where they overlap (which looks ugly)
- */
-static void
-render_overlap(ASS_Renderer *render_priv, ASS_Image **last_tail,
-               ASS_Image **tail)
-{
-    int left, top, bottom, right;
-    int old_left, old_top, w, h, cur_left, cur_top;
-    int x, y, opos, cpos;
-    char m;
-    CompositeHashKey hk;
-    CompositeHashValue *hv;
-    CompositeHashValue chv;
-    int ax = (*last_tail)->dst_x;
-    int ay = (*last_tail)->dst_y;
-    int aw = (*last_tail)->w;
-    int as = (*last_tail)->stride;
-    int ah = (*last_tail)->h;
-    int bx = (*tail)->dst_x;
-    int by = (*tail)->dst_y;
-    int bw = (*tail)->w;
-    int bs = (*tail)->stride;
-    int bh = (*tail)->h;
-    unsigned char *a;
-    unsigned char *b;
-
-    if ((*last_tail)->bitmap == (*tail)->bitmap)
-        return;
-
-    if ((*last_tail)->color != (*tail)->color)
-        return;
-
-    // Calculate overlap coordinates
-    left = (ax > bx) ? ax : bx;
-    top = (ay > by) ? ay : by;
-    right = ((ax + aw) < (bx + bw)) ? (ax + aw) : (bx + bw);
-    bottom = ((ay + ah) < (by + bh)) ? (ay + ah) : (by + bh);
-    if ((right <= left) || (bottom <= top))
-        return;
-    old_left = left - ax;
-    old_top = top - ay;
-    w = right - left;
-    h = bottom - top;
-    cur_left = left - bx;
-    cur_top = top - by;
-
-    // Query cache
-    hk.a = (*last_tail)->bitmap;
-    hk.b = (*tail)->bitmap;
-    hk.aw = aw;
-    hk.ah = ah;
-    hk.bw = bw;
-    hk.bh = bh;
-    hk.ax = ax;
-    hk.ay = ay;
-    hk.bx = bx;
-    hk.by = by;
-    hk.as = as;
-    hk.bs = bs;
-    hv = cache_find_composite(render_priv->cache.composite_cache, &hk);
-    if (hv) {
-        (*last_tail)->bitmap = hv->a;
-        (*tail)->bitmap = hv->b;
-        return;
-    }
-    // Allocate new bitmaps and copy over data
-    a = clone_bitmap_buffer(*last_tail);
-    b = clone_bitmap_buffer(*tail);
-
-    // Blend overlapping area
-    for (y = 0; y < h; y++)
-        for (x = 0; x < w; x++) {
-            opos = (old_top + y) * (as) + (old_left + x);
-            cpos = (cur_top + y) * (bs) + (cur_left + x);
-            m = FFMIN(a[opos] + b[cpos], 0xff);
-            (*last_tail)->bitmap[opos] = 0;
-            (*tail)->bitmap[cpos] = m;
-        }
-
-    // Insert bitmaps into the cache
-    chv.a = (*last_tail)->bitmap;
-    chv.b = (*tail)->bitmap;
-    cache_add_composite(render_priv->cache.composite_cache, &hk, &chv);
-}
-
-static void free_list_add(ASS_Renderer *render_priv, void *object)
-{
-    if (!render_priv->free_head) {
-        render_priv->free_head = calloc(1, sizeof(FreeList));
-        render_priv->free_head->object = object;
-        render_priv->free_tail = render_priv->free_head;
-    } else {
-        FreeList *l = calloc(1, sizeof(FreeList));
-        l->object = object;
-        render_priv->free_tail->next = l;
-        render_priv->free_tail = render_priv->free_tail->next;
-    }
-}
-
-/**
- * Iterate through a list of bitmaps and blend with clip vector, if
- * applicable. The blended bitmaps are added to a free list which is freed
- * at the start of a new frame.
- */
-static void blend_vector_clip(ASS_Renderer *render_priv,
-                              ASS_Image *head)
-{
-    FT_Glyph glyph;
-    FT_BitmapGlyph clip_bm;
-    ASS_Image *cur;
-    ASS_Drawing *drawing = render_priv->state.clip_drawing;
-    GlyphHashKey key;
-    GlyphHashValue *val;
-    int error;
-
-    if (!drawing)
-        return;
-
-    // Try to get mask from cache
-    ass_drawing_hash(drawing);
-    memset(&key, 0, sizeof(key));
-    key.ch = -2;
-    key.drawing_hash = drawing->hash;
-    val = cache_find_glyph(render_priv->cache.glyph_cache, &key);
-
-    if (val) {
-        clip_bm = (FT_BitmapGlyph) val->glyph;
-    } else {
-        GlyphHashValue v;
-
-        // Not found in cache, parse and rasterize it
-        glyph = (FT_Glyph) *ass_drawing_parse(drawing, 1);
-        if (!glyph) {
-            ass_msg(render_priv->library, MSGL_WARN,
-                    "Clip vector parsing failed. Skipping.");
-            goto blend_vector_error;
-        }
-
-        // We need to translate the clip according to screen borders
-        if (render_priv->settings.left_margin != 0 ||
-            render_priv->settings.top_margin != 0) {
-            FT_Vector trans = {
-                int_to_d6(render_priv->settings.left_margin),
-                -int_to_d6(render_priv->settings.top_margin),
-            };
-            FT_Outline_Translate(&drawing->glyph->outline,
-                                 trans.x, trans.y);
-        }
-
-        // Check glyph bounding box size
-        if (check_glyph_area(render_priv->library, glyph)) {
-            FT_Done_Glyph(glyph);
-            glyph = 0;
-            goto blend_vector_error;
-        }
-
-        ass_msg(render_priv->library, MSGL_DBG2,
-                "Parsed vector clip: scales (%f, %f) string [%s]\n",
-                drawing->scale_x, drawing->scale_y, drawing->text);
-
-        error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
-        if (error) {
-            ass_msg(render_priv->library, MSGL_WARN,
-                "Clip vector rasterization failed: %d. Skipping.", error);
-            FT_Done_Glyph(glyph);
-            glyph = 0;
-        }
-
-blend_vector_error:
-        clip_bm = (FT_BitmapGlyph) glyph;
-
-        // Add to cache
-        memset(&v, 0, sizeof(v));
-        v.glyph = glyph;
-        cache_add_glyph(render_priv->cache.glyph_cache, &key, &v);
-    }
-
-    if (!clip_bm) goto blend_vector_exit;
-
-    // Iterate through bitmaps and blend/clip them
-    for (cur = head; cur; cur = cur->next) {
-        int left, top, right, bottom, apos, bpos, y, x, w, h;
-        int ax, ay, aw, ah, as;
-        int bx, by, bw, bh, bs;
-        int aleft, atop, bleft, btop;
-        unsigned char *abuffer, *bbuffer, *nbuffer;
-
-        abuffer = cur->bitmap;
-        bbuffer = clip_bm->bitmap.buffer;
-        ax = cur->dst_x;
-        ay = cur->dst_y;
-        aw = cur->w;
-        ah = cur->h;
-        as = cur->stride;
-        bx = clip_bm->left;
-        by = -clip_bm->top;
-        bw = clip_bm->bitmap.width;
-        bh = clip_bm->bitmap.rows;
-        bs = clip_bm->bitmap.pitch;
-
-        // Calculate overlap coordinates
-        left = (ax > bx) ? ax : bx;
-        top = (ay > by) ? ay : by;
-        right = ((ax + aw) < (bx + bw)) ? (ax + aw) : (bx + bw);
-        bottom = ((ay + ah) < (by + bh)) ? (ay + ah) : (by + bh);
-        aleft = left - ax;
-        atop = top - ay;
-        w = right - left;
-        h = bottom - top;
-        bleft = left - bx;
-        btop = top - by;
-
-        if (render_priv->state.clip_drawing_mode) {
-            // Inverse clip
-            if (ax + aw < bx || ay + ah < by || ax > bx + bw ||
-                ay > by + bh) {
-                continue;
-            }
-
-            // Allocate new buffer and add to free list
-            nbuffer = malloc(as * ah);
-            if (!nbuffer) goto blend_vector_exit;
-            free_list_add(render_priv, nbuffer);
-
-            // Blend together
-            memcpy(nbuffer, abuffer, as * (ah - 1) + aw);
-            for (y = 0; y < h; y++)
-                for (x = 0; x < w; x++) {
-                    apos = (atop + y) * as + aleft + x;
-                    bpos = (btop + y) * bs + bleft + x;
-                    nbuffer[apos] = FFMAX(0, abuffer[apos] - bbuffer[bpos]);
-                }
-        } else {
-            // Regular clip
-            if (ax + aw < bx || ay + ah < by || ax > bx + bw ||
-                ay > by + bh) {
-                cur->w = cur->h = 0;
-                continue;
-            }
-
-            // Allocate new buffer and add to free list
-            nbuffer = calloc(as, ah);
-            if (!nbuffer) goto blend_vector_exit;
-            free_list_add(render_priv, nbuffer);
-
-            // Blend together
-            for (y = 0; y < h; y++)
-                for (x = 0; x < w; x++) {
-                    apos = (atop + y) * as + aleft + x;
-                    bpos = (btop + y) * bs + bleft + x;
-                    nbuffer[apos] = (abuffer[apos] * bbuffer[bpos] + 255) >> 8;
-                }
-        }
-        cur->bitmap = nbuffer;
-    }
-
-blend_vector_exit:
-    ass_drawing_free(render_priv->state.clip_drawing);
-    render_priv->state.clip_drawing = 0;
-}
-
-/**
- * \brief Convert TextInfo struct to ASS_Image list
- * Splits glyphs in halves when needed (for \kf karaoke).
- */
-static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x, int dst_y)
-{
-    int pen_x, pen_y;
-    int i;
-    Bitmap *bm;
-    ASS_Image *head;
-    ASS_Image **tail = &head;
-    ASS_Image **last_tail = 0;
-    ASS_Image **here_tail = 0;
-    TextInfo *text_info = &render_priv->text_info;
-
-    for (i = 0; i < text_info->length; ++i) {
-        GlyphInfo *info = text_info->glyphs + i;
-        if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_s
-            || (info->shadow_x == 0 && info->shadow_y == 0) || info->skip)
-            continue;
-
-        pen_x =
-            dst_x + (info->pos.x >> 6) +
-            (int) (info->shadow_x * render_priv->border_scale);
-        pen_y =
-            dst_y + (info->pos.y >> 6) +
-            (int) (info->shadow_y * render_priv->border_scale);
-        bm = info->bm_s;
-
-        here_tail = tail;
-        tail =
-            render_glyph(render_priv, bm, pen_x, pen_y, info->c[3], 0,
-                         1000000, tail);
-        if (last_tail && tail != here_tail && ((info->c[3] & 0xff) > 0))
-            render_overlap(render_priv, last_tail, here_tail);
-
-        last_tail = here_tail;
-    }
-
-    last_tail = 0;
-    for (i = 0; i < text_info->length; ++i) {
-        GlyphInfo *info = text_info->glyphs + i;
-        if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_o
-            || info->skip)
-            continue;
-
-        pen_x = dst_x + (info->pos.x >> 6);
-        pen_y = dst_y + (info->pos.y >> 6);
-        bm = info->bm_o;
-
-        if ((info->effect_type == EF_KARAOKE_KO)
-            && (info->effect_timing <= (info->bbox.xMax >> 6))) {
-            // do nothing
-        } else {
-            here_tail = tail;
-            tail =
-                render_glyph(render_priv, bm, pen_x, pen_y, info->c[2],
-                             0, 1000000, tail);
-            if (last_tail && tail != here_tail && ((info->c[2] & 0xff) > 0))
-                render_overlap(render_priv, last_tail, here_tail);
-
-            last_tail = here_tail;
-        }
-    }
-
-    for (i = 0; i < text_info->length; ++i) {
-        GlyphInfo *info = text_info->glyphs + i;
-        if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm
-            || info->skip)
-            continue;
-
-        pen_x = dst_x + (info->pos.x >> 6);
-        pen_y = dst_y + (info->pos.y >> 6);
-        bm = info->bm;
-
-        if ((info->effect_type == EF_KARAOKE)
-            || (info->effect_type == EF_KARAOKE_KO)) {
-            if (info->effect_timing > (info->bbox.xMax >> 6))
-                tail =
-                    render_glyph(render_priv, bm, pen_x, pen_y,
-                                 info->c[0], 0, 1000000, tail);
-            else
-                tail =
-                    render_glyph(render_priv, bm, pen_x, pen_y,
-                                 info->c[1], 0, 1000000, tail);
-        } else if (info->effect_type == EF_KARAOKE_KF) {
-            tail =
-                render_glyph(render_priv, bm, pen_x, pen_y, info->c[0],
-                             info->c[1], info->effect_timing, tail);
-        } else
-            tail =
-                render_glyph(render_priv, bm, pen_x, pen_y, info->c[0],
-                             0, 1000000, tail);
-    }
-
-    *tail = 0;
-    blend_vector_clip(render_priv, head);
-
-    return head;
-}
-
-static void compute_string_bbox(TextInfo *info, DBBox *bbox)
-{
-    int i;
-
-    if (info->length > 0) {
-        bbox->xMin = 32000;
-        bbox->xMax = -32000;
-        bbox->yMin = -1 * info->lines[0].asc + d6_to_double(info->glyphs[0].pos.y);
-        bbox->yMax = info->height - info->lines[0].asc +
-                     d6_to_double(info->glyphs[0].pos.y);
-
-        for (i = 0; i < info->length; ++i) {
-            double s, e;
-            if (info->glyphs[i].skip) continue;
-            s = d6_to_double(info->glyphs[i].pos.x);
-            e = s + d6_to_double(info->glyphs[i].advance.x);
-            bbox->xMin = FFMIN(bbox->xMin, s);
-            bbox->xMax = FFMAX(bbox->xMax, e);
-        }
-    } else
-        bbox->xMin = bbox->xMax = bbox->yMin = bbox->yMax = 0.;
-}
-
-/**
- * \brief partially reset render_context to style values
- * Works like {\r}: resets some style overrides
- */
-void reset_render_context(ASS_Renderer *render_priv)
-{
-    render_priv->state.c[0] = render_priv->state.style->PrimaryColour;
-    render_priv->state.c[1] = render_priv->state.style->SecondaryColour;
-    render_priv->state.c[2] = render_priv->state.style->OutlineColour;
-    render_priv->state.c[3] = render_priv->state.style->BackColour;
-    render_priv->state.flags =
-        (render_priv->state.style->Underline ? DECO_UNDERLINE : 0) |
-        (render_priv->state.style->StrikeOut ? DECO_STRIKETHROUGH : 0);
-    render_priv->state.font_size = render_priv->state.style->FontSize;
-
-    free(render_priv->state.family);
-    render_priv->state.family = NULL;
-    render_priv->state.family = strdup(render_priv->state.style->FontName);
-    render_priv->state.treat_family_as_pattern =
-        render_priv->state.style->treat_fontname_as_pattern;
-    render_priv->state.bold = render_priv->state.style->Bold;
-    render_priv->state.italic = render_priv->state.style->Italic;
-    update_font(render_priv);
-
-    change_border(render_priv, -1., -1.);
-    render_priv->state.scale_x = render_priv->state.style->ScaleX;
-    render_priv->state.scale_y = render_priv->state.style->ScaleY;
-    render_priv->state.hspacing = render_priv->state.style->Spacing;
-    render_priv->state.be = 0;
-    render_priv->state.blur = 0.0;
-    render_priv->state.shadow_x = render_priv->state.style->Shadow;
-    render_priv->state.shadow_y = render_priv->state.style->Shadow;
-    render_priv->state.frx = render_priv->state.fry = 0.;
-    render_priv->state.frz = M_PI * render_priv->state.style->Angle / 180.;
-    render_priv->state.fax = render_priv->state.fay = 0.;
-    render_priv->state.wrap_style = render_priv->track->WrapStyle;
-}
-
-/**
- * \brief Start new event. Reset render_priv->state.
- */
-static void
-init_render_context(ASS_Renderer *render_priv, ASS_Event *event)
-{
-    render_priv->state.event = event;
-    render_priv->state.style = render_priv->track->styles + event->Style;
-
-    reset_render_context(render_priv);
-
-    render_priv->state.evt_type = EVENT_NORMAL;
-    render_priv->state.alignment = render_priv->state.style->Alignment;
-    render_priv->state.pos_x = 0;
-    render_priv->state.pos_y = 0;
-    render_priv->state.org_x = 0;
-    render_priv->state.org_y = 0;
-    render_priv->state.have_origin = 0;
-    render_priv->state.clip_x0 = 0;
-    render_priv->state.clip_y0 = 0;
-    render_priv->state.clip_x1 = render_priv->track->PlayResX;
-    render_priv->state.clip_y1 = render_priv->track->PlayResY;
-    render_priv->state.clip_mode = 0;
-    render_priv->state.detect_collisions = 1;
-    render_priv->state.fade = 0;
-    render_priv->state.drawing_mode = 0;
-    render_priv->state.effect_type = EF_NONE;
-    render_priv->state.effect_timing = 0;
-    render_priv->state.effect_skip_timing = 0;
-    ass_drawing_free(render_priv->state.drawing);
-    render_priv->state.drawing = ass_drawing_new(render_priv->fontconfig_priv,
-                                                 render_priv->state.font,
-                                                 render_priv->ftlibrary);
-
-    apply_transition_effects(render_priv, event);
-}
-
-static void free_render_context(ASS_Renderer *render_priv)
-{
-    free(render_priv->state.family);
-    ass_drawing_free(render_priv->state.drawing);
-
-    render_priv->state.family = NULL;
-    render_priv->state.drawing = NULL;
-}
-
-/*
- * Replace the outline of a glyph by a contour which makes up a simple
- * opaque rectangle.
- */
-static void draw_opaque_box(ASS_Renderer *render_priv, uint32_t ch,
-                            FT_Glyph glyph, int sx, int sy)
-{
-    int asc = 0, desc = 0;
-    int i;
-    int adv = d16_to_d6(glyph->advance.x);
-    double scale_y = render_priv->state.scale_y;
-    double scale_x = render_priv->state.scale_x;
-    FT_OutlineGlyph og = (FT_OutlineGlyph) glyph;
-    FT_Outline *ol;
-
-    // to avoid gaps
-    sx = FFMAX(64, sx);
-    sy = FFMAX(64, sy);
-
-    if (ch == -1) {
-        asc = render_priv->state.drawing->asc;
-        desc = render_priv->state.drawing->desc;
-    } else {
-        ass_font_get_asc_desc(render_priv->state.font, ch, &asc, &desc);
-        asc  *= scale_y;
-        desc *= scale_y;
-    }
-
-    // Emulate the WTFish behavior of VSFilter, i.e. double-scale
-    // the sizes of the opaque box.
-    adv += double_to_d6(render_priv->state.hspacing * render_priv->font_scale
-                        * scale_x);
-    adv *= scale_x;
-    sx *= scale_x;
-    sy *= scale_y;
-    desc *= scale_y;
-    desc += asc * (scale_y - 1.0);
-
-    {
-        FT_Vector points[4] = {
-            { -sx,         asc + sy },
-            { adv + sx,    asc + sy },
-            { adv + sx,    -desc - sy },
-            { -sx,         -desc - sy },
-        };
-
-        FT_Outline_Done(render_priv->ftlibrary, &og->outline);
-        FT_Outline_New(render_priv->ftlibrary, 4, 1, &og->outline);
-
-        ol = &og->outline;
-        ol->n_points = ol->n_contours = 0;
-        for (i = 0; i < 4; i++) {
-            ol->points[ol->n_points] = points[i];
-            ol->tags[ol->n_points++] = 1;
-        }
-    }
-    ol->contours[ol->n_contours++] = ol->n_points - 1;
-}
-
-/*
- * Stroke an outline glyph in x/y direction.  Applies various fixups to get
- * around limitations of the FreeType stroker.
- */
-static void stroke_outline_glyph(ASS_Renderer *render_priv,
-                                 FT_OutlineGlyph *glyph, int sx, int sy)
-{
-    if (sx <= 0 && sy <= 0)
-        return;
-
-    fix_freetype_stroker(*glyph, sx, sy);
-
-    // Borders are equal; use the regular stroker
-    if (sx == sy && render_priv->state.stroker) {
-        int error;
-        error = FT_Glyph_StrokeBorder((FT_Glyph *) glyph,
-                                      render_priv->state.stroker, 0, 1);
-        if (error)
-            ass_msg(render_priv->library, MSGL_WARN,
-                    "FT_Glyph_Stroke error: %d", error);
-
-    // "Stroke" with the outline emboldener in two passes.
-    // The outlines look uglier, but the emboldening never adds any points
-    } else {
-        int i;
-        FT_Outline *ol = &(*glyph)->outline;
-        FT_Outline nol;
-        FT_Outline_New(render_priv->ftlibrary, ol->n_points,
-                       ol->n_contours, &nol);
-        FT_Outline_Copy(ol, &nol);
-
-        FT_Outline_Embolden(ol, sx * 2);
-        FT_Outline_Translate(ol, -sx, -sx);
-        FT_Outline_Embolden(&nol, sy * 2);
-        FT_Outline_Translate(&nol, -sy, -sy);
-
-        for (i = 0; i < ol->n_points; i++)
-            ol->points[i].y = nol.points[i].y;
-
-        FT_Outline_Done(render_priv->ftlibrary, &nol);
-    }
-}
-
-/**
- * \brief Prepare glyph hash
- */
-static void
-fill_glyph_hash(ASS_Renderer *priv, GlyphHashKey *key,
-                ASS_Drawing *drawing, uint32_t ch)
-{
-    if (drawing->hash) {
-        key->scale_x = double_to_d16(priv->state.scale_x);
-        key->scale_y = double_to_d16(priv->state.scale_y);
-        key->outline.x = priv->state.border_x * 0xFFFF;
-        key->outline.y = priv->state.border_y * 0xFFFF;
-        key->border_style = priv->state.style->BorderStyle;
-        key->drawing_hash = drawing->hash;
-        // not very clean, but works
-        key->size = drawing->scale;
-        key->ch = -1;
-    } else {
-        key->font = priv->state.font;
-        key->size = priv->state.font_size;
-        key->ch = ch;
-        key->bold = priv->state.bold;
-        key->italic = priv->state.italic;
-        key->scale_x = double_to_d16(priv->state.scale_x);
-        key->scale_y = double_to_d16(priv->state.scale_y);
-        key->outline.x = priv->state.border_x * 0xFFFF;
-        key->outline.y = priv->state.border_y * 0xFFFF;
-        key->flags = priv->state.flags;
-        key->border_style = priv->state.style->BorderStyle;
-    }
-}
-
-/**
- * \brief Get normal and outline (border) glyphs
- * \param symbol ucs4 char
- * \param info out: struct filled with extracted data
- * Tries to get both glyphs from cache.
- * If they can't be found, gets a glyph from font face, generates outline with FT_Stroker,
- * and add them to cache.
- * The glyphs are returned in info->glyph and info->outline_glyph
- */
-static void
-get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info,
-                  ASS_Drawing *drawing)
-{
-    GlyphHashValue *val;
-    GlyphHashKey key;
-
-    memset(&key, 0, sizeof(key));
-    memset(info, 0, sizeof(GlyphInfo));
-
-    fill_glyph_hash(render_priv, &key, drawing, symbol);
-    val = cache_find_glyph(render_priv->cache.glyph_cache, &key);
-    if (val) {
-        info->glyph = val->glyph;
-        info->outline_glyph = val->outline_glyph;
-        info->bbox = val->bbox_scaled;
-        info->advance.x = val->advance.x;
-        info->advance.y = val->advance.y;
-        if (drawing->hash) {
-            drawing->asc = val->asc;
-            drawing->desc = val->desc;
-        }
-    } else {
-        GlyphHashValue v;
-        if (drawing->hash) {
-            if(!ass_drawing_parse(drawing, 0))
-                return;
-            info->glyph = (FT_Glyph) drawing->glyph;
-        } else {
-            info->glyph =
-                ass_font_get_glyph(render_priv->fontconfig_priv,
-                                   render_priv->state.font, symbol,
-                                   render_priv->settings.hinting,
-                                   render_priv->state.flags);
-        }
-        if (!info->glyph)
-            return;
-
-        info->advance.x = d16_to_d6(info->glyph->advance.x);
-        info->advance.y = d16_to_d6(info->glyph->advance.y);
-        FT_Glyph_Get_CBox(info->glyph, FT_GLYPH_BBOX_SUBPIXELS, &info->bbox);
-
-        if (render_priv->state.style->BorderStyle == 3 &&
-            (render_priv->state.border_x > 0||
-             render_priv->state.border_y > 0)) {
-            FT_Glyph_Copy(info->glyph, &info->outline_glyph);
-            draw_opaque_box(render_priv, symbol, info->outline_glyph,
-                            double_to_d6(render_priv->state.border_x *
-                                         render_priv->border_scale),
-                            double_to_d6(render_priv->state.border_y *
-                                         render_priv->border_scale));
-        } else if ((render_priv->state.border_x > 0
-                    || render_priv->state.border_y > 0)
-                   && key.scale_x && key.scale_y) {
-
-            FT_Glyph_Copy(info->glyph, &info->outline_glyph);
-            stroke_outline_glyph(render_priv,
-                                 (FT_OutlineGlyph *) &info->outline_glyph,
-                                 double_to_d6(render_priv->state.border_x *
-                                              render_priv->border_scale),
-                                 double_to_d6(render_priv->state.border_y *
-                                              render_priv->border_scale));
-        }
-
-        memset(&v, 0, sizeof(v));
-        v.glyph = info->glyph;
-        v.outline_glyph = info->outline_glyph;
-        v.advance = info->advance;
-        v.bbox_scaled = info->bbox;
-        if (drawing->hash) {
-            v.asc = drawing->asc;
-            v.desc = drawing->desc;
-        }
-        cache_add_glyph(render_priv->cache.glyph_cache, &key, &v);
-    }
-}
-
-/**
- * \brief Apply transformation to outline points of a glyph
- * Applies rotations given by frx, fry and frz and projects the points back
- * onto the screen plane.
- */
-static void
-transform_3d_points(FT_Vector shift, FT_Glyph glyph, double frx, double fry,
-                    double frz, double fax, double fay, double scale,
-                    int yshift)
-{
-    double sx = sin(frx);
-    double sy = sin(fry);
-    double sz = sin(frz);
-    double cx = cos(frx);
-    double cy = cos(fry);
-    double cz = cos(frz);
-    FT_Outline *outline = &((FT_OutlineGlyph) glyph)->outline;
-    FT_Vector *p = outline->points;
-    double x, y, z, xx, yy, zz;
-    int i, dist;
-
-    dist = 20000 * scale;
-    for (i = 0; i < outline->n_points; i++) {
-        x = (double) p[i].x + shift.x + (fax * (yshift - p[i].y));
-        y = (double) p[i].y + shift.y + (-fay * p[i].x);
-        z = 0.;
-
-        xx = x * cz + y * sz;
-        yy = -(x * sz - y * cz);
-        zz = z;
-
-        x = xx;
-        y = yy * cx + zz * sx;
-        z = yy * sx - zz * cx;
-
-        xx = x * cy + z * sy;
-        yy = y;
-        zz = x * sy - z * cy;
-
-        zz = FFMAX(zz, 1000 - dist);
-
-        x = (xx * dist) / (zz + dist);
-        y = (yy * dist) / (zz + dist);
-        p[i].x = x - shift.x + 0.5;
-        p[i].y = y - shift.y + 0.5;
-    }
-}
-
-/**
- * \brief Apply 3d transformation to several objects
- * \param shift FreeType vector
- * \param glyph FreeType glyph
- * \param glyph2 FreeType glyph
- * \param frx x-axis rotation angle
- * \param fry y-axis rotation angle
- * \param frz z-axis rotation angle
- * Rotates both glyphs by frx, fry and frz. Shift vector is added before rotation and subtracted after it.
- */
-static void
-transform_3d(FT_Vector shift, FT_Glyph *glyph, FT_Glyph *glyph2,
-             double frx, double fry, double frz, double fax, double fay,
-             double scale, int yshift)
-{
-    frx = -frx;
-    frz = -frz;
-    if (frx != 0. || fry != 0. || frz != 0. || fax != 0. || fay != 0.) {
-        if (glyph && *glyph)
-            transform_3d_points(shift, *glyph, frx, fry, frz,
-                                fax, fay, scale, yshift);
-
-        if (glyph2 && *glyph2)
-            transform_3d_points(shift, *glyph2, frx, fry, frz,
-                                fax, fay, scale, yshift);
-    }
-}
-
-/**
- * \brief Get bitmaps for a glyph
- * \param info glyph info
- * Tries to get glyph bitmaps from bitmap cache.
- * If they can't be found, they are generated by rotating and rendering the glyph.
- * After that, bitmaps are added to the cache.
- * They are returned in info->bm (glyph), info->bm_o (outline) and info->bm_s (shadow).
- */
-static void
-get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
-{
-    BitmapHashValue *val;
-    BitmapHashKey *key = &info->hash_key;
-
-    val = cache_find_bitmap(render_priv->cache.bitmap_cache, key);
-
-    if (val) {
-        info->bm = val->bm;
-        info->bm_o = val->bm_o;
-        info->bm_s = val->bm_s;
-    } else {
-        FT_Vector shift;
-        BitmapHashValue hash_val;
-        int error;
-        double fax_scaled, fay_scaled;
-        info->bm = info->bm_o = info->bm_s = 0;
-        if (info->glyph && info->symbol != '\n' && info->symbol != 0
-            && !info->skip) {
-            FT_Glyph glyph;
-            FT_Glyph outline;
-            double scale_x = render_priv->font_scale_x;
-
-            // PAR correction scaling
-            FT_Matrix m = { double_to_d16(scale_x), 0, 0, double_to_d16(1.0) };
-
-            FT_Glyph_Copy(info->glyph, &glyph);
-            FT_Glyph_Copy(info->outline_glyph, &outline);
-            // calculating rotation shift vector (from rotation origin to the glyph basepoint)
-            shift.x = key->shift_x;
-            shift.y = key->shift_y;
-            fax_scaled = info->fax *
-                         render_priv->state.scale_x;
-            fay_scaled = info->fay * render_priv->state.scale_y;
-            // apply rotation
-            transform_3d(shift, &glyph, &outline,
-                         info->frx, info->fry, info->frz, fax_scaled,
-                         fay_scaled, render_priv->font_scale, info->asc);
-
-            // subpixel shift
-            if (glyph) {
-                FT_Outline *outl = &((FT_OutlineGlyph) glyph)->outline;
-                if (scale_x != 1.0)
-                    FT_Outline_Transform(outl, &m);
-                FT_Outline_Translate(outl, key->advance.x, -key->advance.y);
-            }
-            if (outline) {
-                FT_Outline *outl = &((FT_OutlineGlyph) outline)->outline;
-                if (scale_x != 1.0)
-                    FT_Outline_Transform(outl, &m);
-                FT_Outline_Translate(outl, key->advance.x, -key->advance.y);
-            }
-            // render glyph
-            error = glyph_to_bitmap(render_priv->library,
-                                    render_priv->synth_priv,
-                                    glyph, outline,
-                                    &info->bm, &info->bm_o,
-                                    &info->bm_s, info->be,
-                                    info->blur * render_priv->border_scale,
-                                    key->shadow_offset, key->border_style);
-            if (error)
-                info->symbol = 0;
-
-            // add bitmaps to cache
-            hash_val.bm_o = info->bm_o;
-            hash_val.bm = info->bm;
-            hash_val.bm_s = info->bm_s;
-            cache_add_bitmap(render_priv->cache.bitmap_cache, key, &hash_val);
-
-            FT_Done_Glyph(glyph);
-            FT_Done_Glyph(outline);
-        }
-    }
-}
-
-/**
- * This function goes through text_info and calculates text parameters.
- * The following text_info fields are filled:
- *   height
- *   lines[].height
- *   lines[].asc
- *   lines[].desc
- */
-static void measure_text(ASS_Renderer *render_priv)
-{
-    TextInfo *text_info = &render_priv->text_info;
-    int cur_line = 0;
-    double max_asc = 0., max_desc = 0.;
-    GlyphInfo *last = NULL;
-    int i;
-    int empty_line = 1;
-    text_info->height = 0.;
-    for (i = 0; i < text_info->length + 1; ++i) {
-        if ((i == text_info->length) || text_info->glyphs[i].linebreak) {
-            if (empty_line && cur_line > 0 && last && i < text_info->length) {
-                max_asc = d6_to_double(last->asc) / 2.0;
-                max_desc = d6_to_double(last->desc) / 2.0;
-            }
-            text_info->lines[cur_line].asc = max_asc;
-            text_info->lines[cur_line].desc = max_desc;
-            text_info->height += max_asc + max_desc;
-            cur_line++;
-            max_asc = max_desc = 0.;
-            empty_line = 1;
-        } else
-            empty_line = 0;
-        if (i < text_info->length) {
-            GlyphInfo *cur = text_info->glyphs + i;
-            if (d6_to_double(cur->asc) > max_asc)
-                max_asc = d6_to_double(cur->asc);
-            if (d6_to_double(cur->desc) > max_desc)
-                max_desc = d6_to_double(cur->desc);
-            if (cur->symbol != '\n' && cur->symbol != 0)
-                last = cur;
-        }
-    }
-    text_info->height +=
-        (text_info->n_lines -
-         1) * render_priv->settings.line_spacing;
-}
-
-/**
- * Mark extra whitespace for later removal.
- */
-#define IS_WHITESPACE(x) ((x->symbol == ' ' || x->symbol == '\n') \
-                          && !x->linebreak)
-static void trim_whitespace(ASS_Renderer *render_priv)
-{
-    int i, j;
-    GlyphInfo *cur;
-    TextInfo *ti = &render_priv->text_info;
-
-    // Mark trailing spaces
-    i = ti->length - 1;
-    cur = ti->glyphs + i;
-    while (i && IS_WHITESPACE(cur)) {
-        cur->skip++;
-        cur = ti->glyphs + --i;
-    }
-
-    // Mark leading whitespace
-    i = 0;
-    cur = ti->glyphs;
-    while (i < ti->length && IS_WHITESPACE(cur)) {
-        cur->skip++;
-        cur = ti->glyphs + ++i;
-    }
-
-    // Mark all extraneous whitespace inbetween
-    for (i = 0; i < ti->length; ++i) {
-        cur = ti->glyphs + i;
-        if (cur->linebreak) {
-            // Mark whitespace before
-            j = i - 1;
-            cur = ti->glyphs + j;
-            while (j && IS_WHITESPACE(cur)) {
-                cur->skip++;
-                cur = ti->glyphs + --j;
-            }
-            // A break itself can contain a whitespace, too
-            cur = ti->glyphs + i;
-            if (cur->symbol == ' ')
-                cur->skip++;
-            // Mark whitespace after
-            j = i + 1;
-            cur = ti->glyphs + j;
-            while (j < ti->length && IS_WHITESPACE(cur)) {
-                cur->skip++;
-                cur = ti->glyphs + ++j;
-            }
-            i = j - 1;
-        }
-    }
-}
-#undef IS_WHITESPACE
-
-/**
- * \brief rearrange text between lines
- * \param max_text_width maximal text line width in pixels
- * The algo is similar to the one in libvo/sub.c:
- * 1. Place text, wrapping it when current line is full
- * 2. Try moving words from the end of a line to the beginning of the next one while it reduces
- * the difference in lengths between this two lines.
- * The result may not be optimal, but usually is good enough.
- *
- * FIXME: implement style 0 and 3 correctly
- */
-static void
-wrap_lines_smart(ASS_Renderer *render_priv, double max_text_width)
-{
-    int i;
-    GlyphInfo *cur, *s1, *e1, *s2, *s3, *w;
-    int last_space;
-    int break_type;
-    int exit;
-    double pen_shift_x;
-    double pen_shift_y;
-    int cur_line;
-    TextInfo *text_info = &render_priv->text_info;
-
-    last_space = -1;
-    text_info->n_lines = 1;
-    break_type = 0;
-    s1 = text_info->glyphs;     // current line start
-    for (i = 0; i < text_info->length; ++i) {
-        int break_at;
-        double s_offset, len;
-        cur = text_info->glyphs + i;
-        break_at = -1;
-        s_offset = d6_to_double(s1->bbox.xMin + s1->pos.x);
-        len = d6_to_double(cur->bbox.xMax + cur->pos.x) - s_offset;
-
-        if (cur->symbol == '\n') {
-            break_type = 2;
-            break_at = i;
-            ass_msg(render_priv->library, MSGL_DBG2,
-                    "forced line break at %d", break_at);
-        }
-
-        if ((len >= max_text_width)
-            && (render_priv->state.wrap_style != 2)) {
-            break_type = 1;
-            break_at = last_space;
-            if (break_at >= 0)
-                ass_msg(render_priv->library, MSGL_DBG2, "line break at %d",
-                        break_at);
-        }
-
-        if (break_at != -1) {
-            // need to use one more line
-            // marking break_at+1 as start of a new line
-            int lead = break_at + 1;    // the first symbol of the new line
-            if (text_info->n_lines >= text_info->max_lines) {
-                // Raise maximum number of lines
-                text_info->max_lines *= 2;
-                text_info->lines = realloc(text_info->lines,
-                                           sizeof(LineInfo) *
-                                           text_info->max_lines);
-            }
-            if (lead < text_info->length)
-                text_info->glyphs[lead].linebreak = break_type;
-            last_space = -1;
-            s1 = text_info->glyphs + lead;
-            s_offset = d6_to_double(s1->bbox.xMin + s1->pos.x);
-            text_info->n_lines++;
-        }
-
-        if (cur->symbol == ' ')
-            last_space = i;
-
-        // make sure the hard linebreak is not forgotten when
-        // there was a new soft linebreak just inserted
-        if (cur->symbol == '\n' && break_type == 1)
-            i--;
-    }
-#define DIFF(x,y) (((x) < (y)) ? (y - x) : (x - y))
-    exit = 0;
-    while (!exit && render_priv->state.wrap_style != 1) {
-        exit = 1;
-        w = s3 = text_info->glyphs;
-        s1 = s2 = 0;
-        for (i = 0; i <= text_info->length; ++i) {
-            cur = text_info->glyphs + i;
-            if ((i == text_info->length) || cur->linebreak) {
-                s1 = s2;
-                s2 = s3;
-                s3 = cur;
-                if (s1 && (s2->linebreak == 1)) {       // have at least 2 lines, and linebreak is 'soft'
-                    double l1, l2, l1_new, l2_new;
-
-                    w = s2;
-                    do {
-                        --w;
-                    } while ((w > s1) && (w->symbol == ' '));
-                    while ((w > s1) && (w->symbol != ' ')) {
-                        --w;
-                    }
-                    e1 = w;
-                    while ((e1 > s1) && (e1->symbol == ' ')) {
-                        --e1;
-                    }
-                    if (w->symbol == ' ')
-                        ++w;
-
-                    l1 = d6_to_double(((s2 - 1)->bbox.xMax + (s2 - 1)->pos.x) -
-                        (s1->bbox.xMin + s1->pos.x));
-                    l2 = d6_to_double(((s3 - 1)->bbox.xMax + (s3 - 1)->pos.x) -
-                        (s2->bbox.xMin + s2->pos.x));
-                    l1_new = d6_to_double(
-                        (e1->bbox.xMax + e1->pos.x) -
-                        (s1->bbox.xMin + s1->pos.x));
-                    l2_new = d6_to_double(
-                        ((s3 - 1)->bbox.xMax + (s3 - 1)->pos.x) -
-                        (w->bbox.xMin + w->pos.x));
-
-                    if (DIFF(l1_new, l2_new) < DIFF(l1, l2)) {
-                        w->linebreak = 1;
-                        s2->linebreak = 0;
-                        exit = 0;
-                    }
-                }
-            }
-            if (i == text_info->length)
-                break;
-        }
-
-    }
-    assert(text_info->n_lines >= 1);
-#undef DIFF
-
-    measure_text(render_priv);
-    trim_whitespace(render_priv);
-
-    pen_shift_x = 0.;
-    pen_shift_y = 0.;
-    cur_line = 1;
-
-    i = 0;
-    cur = text_info->glyphs + i;
-    while (i < text_info->length && cur->skip)
-        cur = text_info->glyphs + ++i;
-    pen_shift_x = d6_to_double(-cur->pos.x);
-
-    for (i = 0; i < text_info->length; ++i) {
-        cur = text_info->glyphs + i;
-        if (cur->linebreak) {
-            double height;
-            while (i < text_info->length && cur->skip && cur->symbol != '\n')
-                cur = text_info->glyphs + ++i;
-            height =
-                text_info->lines[cur_line - 1].desc +
-                text_info->lines[cur_line].asc;
-            cur_line++;
-            pen_shift_x = d6_to_double(-cur->pos.x);
-            pen_shift_y += height + render_priv->settings.line_spacing;
-            ass_msg(render_priv->library, MSGL_DBG2,
-                   "shifting from %d to %d by (%f, %f)", i,
-                   text_info->length - 1, pen_shift_x, pen_shift_y);
-        }
-        cur->pos.x += double_to_d6(pen_shift_x);
-        cur->pos.y += double_to_d6(pen_shift_y);
-    }
-}
-
-/**
- * \brief determine karaoke effects
- * Karaoke effects cannot be calculated during parse stage (get_next_char()),
- * so they are done in a separate step.
- * Parse stage: when karaoke style override is found, its parameters are stored in the next glyph's
- * (the first glyph of the karaoke word)'s effect_type and effect_timing.
- * This function:
- * 1. sets effect_type for all glyphs in the word (_karaoke_ word)
- * 2. sets effect_timing for all glyphs to x coordinate of the border line between the left and right karaoke parts
- * (left part is filled with PrimaryColour, right one - with SecondaryColour).
- */
-static void process_karaoke_effects(ASS_Renderer *render_priv)
-{
-    GlyphInfo *cur, *cur2;
-    GlyphInfo *s1, *e1;      // start and end of the current word
-    GlyphInfo *s2;           // start of the next word
-    int i;
-    int timing;                 // current timing
-    int tm_start, tm_end;       // timings at start and end of the current word
-    int tm_current;
-    double dt;
-    int x;
-    int x_start, x_end;
-
-    tm_current = render_priv->time - render_priv->state.event->Start;
-    timing = 0;
-    s1 = s2 = 0;
-    for (i = 0; i <= render_priv->text_info.length; ++i) {
-        cur = render_priv->text_info.glyphs + i;
-        if ((i == render_priv->text_info.length)
-            || (cur->effect_type != EF_NONE)) {
-            s1 = s2;
-            s2 = cur;
-            if (s1) {
-                e1 = s2 - 1;
-                tm_start = timing + s1->effect_skip_timing;
-                tm_end = tm_start + s1->effect_timing;
-                timing = tm_end;
-                x_start = 1000000;
-                x_end = -1000000;
-                for (cur2 = s1; cur2 <= e1; ++cur2) {
-                    x_start = FFMIN(x_start, d6_to_int(cur2->bbox.xMin + cur2->pos.x));
-                    x_end = FFMAX(x_end, d6_to_int(cur2->bbox.xMax + cur2->pos.x));
-                }
-
-                dt = (tm_current - tm_start);
-                if ((s1->effect_type == EF_KARAOKE)
-                    || (s1->effect_type == EF_KARAOKE_KO)) {
-                    if (dt > 0)
-                        x = x_end + 1;
-                    else
-                        x = x_start;
-                } else if (s1->effect_type == EF_KARAOKE_KF) {
-                    dt /= (tm_end - tm_start);
-                    x = x_start + (x_end - x_start) * dt;
-                } else {
-                    ass_msg(render_priv->library, MSGL_ERR,
-                            "Unknown effect type");
-                    continue;
-                }
-
-                for (cur2 = s1; cur2 <= e1; ++cur2) {
-                    cur2->effect_type = s1->effect_type;
-                    cur2->effect_timing = x - d6_to_int(cur2->pos.x);
-                }
-            }
-        }
-    }
-}
-
-/**
- * \brief Calculate base point for positioning and rotation
- * \param bbox text bbox
- * \param alignment alignment
- * \param bx, by out: base point coordinates
- */
-static void get_base_point(DBBox *bbox, int alignment, double *bx, double *by)
-{
-    const int halign = alignment & 3;
-    const int valign = alignment & 12;
-    if (bx)
-        switch (halign) {
-        case HALIGN_LEFT:
-            *bx = bbox->xMin;
-            break;
-        case HALIGN_CENTER:
-            *bx = (bbox->xMax + bbox->xMin) / 2.0;
-            break;
-        case HALIGN_RIGHT:
-            *bx = bbox->xMax;
-            break;
-        }
-    if (by)
-        switch (valign) {
-        case VALIGN_TOP:
-            *by = bbox->yMin;
-            break;
-        case VALIGN_CENTER:
-            *by = (bbox->yMax + bbox->yMin) / 2.0;
-            break;
-        case VALIGN_SUB:
-            *by = bbox->yMax;
-            break;
-        }
-}
-
-/**
- * Prepare bitmap hash key of a glyph
- */
-static void
-fill_bitmap_hash(ASS_Renderer *priv, BitmapHashKey *hash_key,
-                 ASS_Drawing *drawing, FT_Vector pen, uint32_t code)
-{
-    if (!drawing->hash) {
-        hash_key->font = priv->state.font;
-        hash_key->size = priv->state.font_size;
-        hash_key->bold = priv->state.bold;
-        hash_key->italic = priv->state.italic;
-    } else {
-        hash_key->drawing_hash = drawing->hash;
-        hash_key->size = drawing->scale;
-    }
-    hash_key->ch = code;
-    hash_key->outline.x = double_to_d16(priv->state.border_x);
-    hash_key->outline.y = double_to_d16(priv->state.border_y);
-    hash_key->scale_x = double_to_d16(priv->state.scale_x);
-    hash_key->scale_y = double_to_d16(priv->state.scale_y);
-    hash_key->frx = rot_key(priv->state.frx);
-    hash_key->fry = rot_key(priv->state.fry);
-    hash_key->frz = rot_key(priv->state.frz);
-    hash_key->fax = double_to_d16(priv->state.fax);
-    hash_key->fay = double_to_d16(priv->state.fay);
-    hash_key->be = priv->state.be;
-    hash_key->blur = priv->state.blur;
-    hash_key->border_style = priv->state.style->BorderStyle;
-    hash_key->shadow_offset.x = double_to_d6(
-            priv->state.shadow_x * priv->border_scale -
-            (int) (priv->state.shadow_x * priv->border_scale));
-    hash_key->shadow_offset.y = double_to_d6(
-            priv->state.shadow_y * priv->border_scale -
-            (int) (priv->state.shadow_y * priv->border_scale));
-    hash_key->flags = priv->state.flags;
-}
-
-/**
- * \brief Main ass rendering function, glues everything together
- * \param event event to render
- * \param event_images struct containing resulting images, will also be initialized
- * Process event, appending resulting ASS_Image's to images_root.
- */
-static int
-ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
-                 EventImages *event_images)
-{
-    char *p;
-    FT_UInt previous;
-    FT_UInt num_glyphs;
-    FT_Vector pen;
-    unsigned code;
-    DBBox bbox;
-    int i, j;
-    int MarginL, MarginR, MarginV;
-    int last_break;
-    int alignment, halign, valign;
-    int kern = render_priv->track->Kerning;
-    double device_x = 0;
-    double device_y = 0;
-    TextInfo *text_info = &render_priv->text_info;
-    GlyphInfo *glyphs = render_priv->text_info.glyphs;
-    ASS_Drawing *drawing;
-
-    if (event->Style >= render_priv->track->n_styles) {
-        ass_msg(render_priv->library, MSGL_WARN, "No style found");
-        return 1;
-    }
-    if (!event->Text) {
-        ass_msg(render_priv->library, MSGL_WARN, "Empty event");
-        return 1;
-    }
-
-    init_render_context(render_priv, event);
-
-    drawing = render_priv->state.drawing;
-    text_info->length = 0;
-    pen.x = 0;
-    pen.y = 0;
-    previous = 0;
-    num_glyphs = 0;
-    p = event->Text;
-    // Event parsing.
-    while (1) {
-        // get next char, executing style override
-        // this affects render_context
-        do {
-            code = get_next_char(render_priv, &p);
-            if (render_priv->state.drawing_mode && code)
-                ass_drawing_add_char(drawing, (char) code);
-        } while (code && render_priv->state.drawing_mode);      // skip everything in drawing mode
-
-        // Parse drawing
-        if (drawing->i) {
-            drawing->scale_x = render_priv->state.scale_x *
-                                     render_priv->font_scale;
-            drawing->scale_y = render_priv->state.scale_y *
-                                     render_priv->font_scale;
-            ass_drawing_hash(drawing);
-            p--;
-            code = -1;
-        }
-
-        // face could have been changed in get_next_char
-        if (!render_priv->state.font) {
-            free_render_context(render_priv);
-            return 1;
-        }
-
-        if (code == 0)
-            break;
-
-        if (text_info->length >= text_info->max_glyphs) {
-            // Raise maximum number of glyphs
-            text_info->max_glyphs *= 2;
-            text_info->glyphs = glyphs =
-                realloc(text_info->glyphs,
-                        sizeof(GlyphInfo) * text_info->max_glyphs);
-        }
-
-        // Add kerning to pen
-        if (kern && previous && code && !drawing->hash) {
-            FT_Vector delta;
-            delta =
-                ass_font_get_kerning(render_priv->state.font, previous,
-                                     code);
-            pen.x += delta.x * render_priv->state.scale_x;
-            pen.y += delta.y * render_priv->state.scale_y;
-        }
-
-        ass_font_set_transform(render_priv->state.font,
-                               render_priv->state.scale_x,
-                               render_priv->state.scale_y, NULL);
-
-        get_outline_glyph(render_priv, code,
-                          glyphs + text_info->length, drawing);
-
-        // Add additional space after italic to non-italic style changes
-        if (text_info->length &&
-            glyphs[text_info->length - 1].hash_key.italic &&
-            !render_priv->state.italic) {
-            int back = text_info->length - 1;
-            GlyphInfo *og = &glyphs[back];
-            while (back && og->bbox.xMax - og->bbox.xMin == 0
-                   && og->hash_key.italic)
-                og = &glyphs[--back];
-            if (og->bbox.xMax > og->advance.x) {
-                // The FreeType oblique slants by 6/16
-                pen.x += og->bbox.yMax * 0.375;
-            }
-        }
-
-        glyphs[text_info->length].pos.x = pen.x;
-        glyphs[text_info->length].pos.y = pen.y;
-
-        pen.x += glyphs[text_info->length].advance.x;
-        pen.x += double_to_d6(render_priv->state.hspacing *
-                              render_priv->font_scale
-                              * render_priv->state.scale_x);
-        pen.y += glyphs[text_info->length].advance.y;
-        pen.y += (render_priv->state.fay * render_priv->state.scale_y) *
-                 glyphs[text_info->length].advance.x;
-
-        previous = code;
-
-        glyphs[text_info->length].symbol = code;
-        glyphs[text_info->length].linebreak = 0;
-        for (i = 0; i < 4; ++i) {
-            uint32_t clr = render_priv->state.c[i];
-            change_alpha(&clr,
-                         mult_alpha(_a(clr), render_priv->state.fade), 1.);
-            glyphs[text_info->length].c[i] = clr;
-        }
-        glyphs[text_info->length].effect_type = render_priv->state.effect_type;
-        glyphs[text_info->length].effect_timing =
-            render_priv->state.effect_timing;
-        glyphs[text_info->length].effect_skip_timing =
-            render_priv->state.effect_skip_timing;
-        glyphs[text_info->length].be = render_priv->state.be;
-        glyphs[text_info->length].blur = render_priv->state.blur;
-        glyphs[text_info->length].shadow_x = render_priv->state.shadow_x;
-        glyphs[text_info->length].shadow_y = render_priv->state.shadow_y;
-        glyphs[text_info->length].frx = render_priv->state.frx;
-        glyphs[text_info->length].fry = render_priv->state.fry;
-        glyphs[text_info->length].frz = render_priv->state.frz;
-        glyphs[text_info->length].fax = render_priv->state.fax;
-        glyphs[text_info->length].fay = render_priv->state.fay;
-        if (drawing->hash) {
-            glyphs[text_info->length].asc = drawing->asc;
-            glyphs[text_info->length].desc = drawing->desc;
-        } else {
-            ass_font_get_asc_desc(render_priv->state.font, code,
-                                  &glyphs[text_info->length].asc,
-                                  &glyphs[text_info->length].desc);
-
-            glyphs[text_info->length].asc *= render_priv->state.scale_y;
-            glyphs[text_info->length].desc *= render_priv->state.scale_y;
-        }
-
-        // fill bitmap hash
-        fill_bitmap_hash(render_priv, &glyphs[text_info->length].hash_key,
-                         drawing, pen, code);
-
-        text_info->length++;
-
-        render_priv->state.effect_type = EF_NONE;
-        render_priv->state.effect_timing = 0;
-        render_priv->state.effect_skip_timing = 0;
-
-        if (drawing->hash) {
-            ass_drawing_free(drawing);
-            drawing = render_priv->state.drawing =
-                ass_drawing_new(render_priv->fontconfig_priv,
-                    render_priv->state.font,
-                    render_priv->ftlibrary);
-        }
-    }
-
-
-    if (text_info->length == 0) {
-        // no valid symbols in the event; this can be smth like {comment}
-        free_render_context(render_priv);
-        return 1;
-    }
-
-    // depends on glyph x coordinates being monotonous, so it should be done before line wrap
-    process_karaoke_effects(render_priv);
-
-    // alignments
-    alignment = render_priv->state.alignment;
-    halign = alignment & 3;
-    valign = alignment & 12;
-
-    MarginL =
-        (event->MarginL) ? event->MarginL : render_priv->state.style->MarginL;
-    MarginR =
-        (event->MarginR) ? event->MarginR : render_priv->state.style->MarginR;
-    MarginV =
-        (event->MarginV) ? event->MarginV : render_priv->state.style->MarginV;
-
-    if (render_priv->state.evt_type != EVENT_HSCROLL) {
-        double max_text_width;
-
-        // calculate max length of a line
-        max_text_width =
-            x2scr(render_priv,
-                  render_priv->track->PlayResX - MarginR) -
-            x2scr(render_priv, MarginL);
-
-        // rearrange text in several lines
-        wrap_lines_smart(render_priv, max_text_width);
-
-        // align text
-        last_break = -1;
-        for (i = 1; i < text_info->length + 1; ++i) {   // (text_info->length + 1) is the end of the last line
-            if ((i == text_info->length)
-                || glyphs[i].linebreak) {
-                double width, shift = 0;
-                GlyphInfo *first_glyph =
-                    glyphs + last_break + 1;
-                GlyphInfo *last_glyph = glyphs + i - 1;
-
-                while (first_glyph < last_glyph && first_glyph->skip)
-                    first_glyph++;
-
-                while ((last_glyph > first_glyph)
-                       && ((last_glyph->symbol == '\n')
-                           || (last_glyph->symbol == 0)
-                           || (last_glyph->skip)))
-                    last_glyph--;
-
-                width = d6_to_double(
-                    last_glyph->pos.x + last_glyph->advance.x -
-                    first_glyph->pos.x);
-                if (halign == HALIGN_LEFT) {    // left aligned, no action
-                    shift = 0;
-                } else if (halign == HALIGN_RIGHT) {    // right aligned
-                    shift = max_text_width - width;
-                } else if (halign == HALIGN_CENTER) {   // centered
-                    shift = (max_text_width - width) / 2.0;
-                }
-                for (j = last_break + 1; j < i; ++j) {
-                    glyphs[j].pos.x += double_to_d6(shift);
-                }
-                last_break = i - 1;
-            }
-        }
-    } else {                    // render_priv->state.evt_type == EVENT_HSCROLL
-        measure_text(render_priv);
-    }
-
-    // determing text bounding box
-    compute_string_bbox(text_info, &bbox);
-
-    // determine device coordinates for text
-
-    // x coordinate for everything except positioned events
-    if (render_priv->state.evt_type == EVENT_NORMAL ||
-        render_priv->state.evt_type == EVENT_VSCROLL) {
-        device_x = x2scr(render_priv, MarginL);
-    } else if (render_priv->state.evt_type == EVENT_HSCROLL) {
-        if (render_priv->state.scroll_direction == SCROLL_RL)
-            device_x =
-                x2scr(render_priv,
-                      render_priv->track->PlayResX -
-                      render_priv->state.scroll_shift);
-        else if (render_priv->state.scroll_direction == SCROLL_LR)
-            device_x =
-                x2scr(render_priv,
-                      render_priv->state.scroll_shift) - (bbox.xMax -
-                                                          bbox.xMin);
-    }
-
-    // y coordinate for everything except positioned events
-    if (render_priv->state.evt_type == EVENT_NORMAL ||
-        render_priv->state.evt_type == EVENT_HSCROLL) {
-        if (valign == VALIGN_TOP) {     // toptitle
-            device_y =
-                y2scr_top(render_priv,
-                          MarginV) + text_info->lines[0].asc;
-        } else if (valign == VALIGN_CENTER) {   // midtitle
-            double scr_y =
-                y2scr(render_priv, render_priv->track->PlayResY / 2.0);
-            device_y = scr_y - (bbox.yMax + bbox.yMin) / 2.0;
-        } else {                // subtitle
-            double scr_y;
-            if (valign != VALIGN_SUB)
-                ass_msg(render_priv->library, MSGL_V,
-                       "Invalid valign, assuming 0 (subtitle)");
-            scr_y =
-                y2scr_sub(render_priv,
-                          render_priv->track->PlayResY - MarginV);
-            device_y = scr_y;
-            device_y -= text_info->height;
-            device_y += text_info->lines[0].asc;
-        }
-    } else if (render_priv->state.evt_type == EVENT_VSCROLL) {
-        if (render_priv->state.scroll_direction == SCROLL_TB)
-            device_y =
-                y2scr(render_priv,
-                      render_priv->state.clip_y0 +
-                      render_priv->state.scroll_shift) - (bbox.yMax -
-                                                          bbox.yMin);
-        else if (render_priv->state.scroll_direction == SCROLL_BT)
-            device_y =
-                y2scr(render_priv,
-                      render_priv->state.clip_y1 -
-                      render_priv->state.scroll_shift);
-    }
-
-    // positioned events are totally different
-    if (render_priv->state.evt_type == EVENT_POSITIONED) {
-        double base_x = 0;
-        double base_y = 0;
-        ass_msg(render_priv->library, MSGL_DBG2, "positioned event at %f, %f",
-               render_priv->state.pos_x, render_priv->state.pos_y);
-        get_base_point(&bbox, alignment, &base_x, &base_y);
-        device_x =
-            x2scr_pos(render_priv, render_priv->state.pos_x) - base_x;
-        device_y =
-            y2scr_pos(render_priv, render_priv->state.pos_y) - base_y;
-    }
-
-    // fix clip coordinates (they depend on alignment)
-    if (render_priv->state.evt_type == EVENT_NORMAL ||
-        render_priv->state.evt_type == EVENT_HSCROLL ||
-        render_priv->state.evt_type == EVENT_VSCROLL) {
-        render_priv->state.clip_x0 =
-            x2scr_scaled(render_priv, render_priv->state.clip_x0);
-        render_priv->state.clip_x1 =
-            x2scr_scaled(render_priv, render_priv->state.clip_x1);
-        if (valign == VALIGN_TOP) {
-            render_priv->state.clip_y0 =
-                y2scr_top(render_priv, render_priv->state.clip_y0);
-            render_priv->state.clip_y1 =
-                y2scr_top(render_priv, render_priv->state.clip_y1);
-        } else if (valign == VALIGN_CENTER) {
-            render_priv->state.clip_y0 =
-                y2scr(render_priv, render_priv->state.clip_y0);
-            render_priv->state.clip_y1 =
-                y2scr(render_priv, render_priv->state.clip_y1);
-        } else if (valign == VALIGN_SUB) {
-            render_priv->state.clip_y0 =
-                y2scr_sub(render_priv, render_priv->state.clip_y0);
-            render_priv->state.clip_y1 =
-                y2scr_sub(render_priv, render_priv->state.clip_y1);
-        }
-    } else if (render_priv->state.evt_type == EVENT_POSITIONED) {
-        render_priv->state.clip_x0 =
-            x2scr_pos_scaled(render_priv, render_priv->state.clip_x0);
-        render_priv->state.clip_x1 =
-            x2scr_pos_scaled(render_priv, render_priv->state.clip_x1);
-        render_priv->state.clip_y0 =
-            y2scr_pos(render_priv, render_priv->state.clip_y0);
-        render_priv->state.clip_y1 =
-            y2scr_pos(render_priv, render_priv->state.clip_y1);
-    }
-
-    // calculate rotation parameters
-    {
-        DVector center;
-
-        if (render_priv->state.have_origin) {
-            center.x = x2scr(render_priv, render_priv->state.org_x);
-            center.y = y2scr(render_priv, render_priv->state.org_y);
-        } else {
-            double bx = 0., by = 0.;
-            get_base_point(&bbox, alignment, &bx, &by);
-            center.x = device_x + bx;
-            center.y = device_y + by;
-        }
-
-        for (i = 0; i < text_info->length; ++i) {
-            GlyphInfo *info = glyphs + i;
-
-            if (info->hash_key.frx || info->hash_key.fry
-                || info->hash_key.frz || info->hash_key.fax
-                || info->hash_key.fay) {
-                info->hash_key.shift_x = info->pos.x + double_to_d6(device_x - center.x);
-                info->hash_key.shift_y =
-                    -(info->pos.y + double_to_d6(device_y - center.y));
-            } else {
-                info->hash_key.shift_x = 0;
-                info->hash_key.shift_y = 0;
-            }
-        }
-    }
-
-    // convert glyphs to bitmaps
-    device_x *= render_priv->font_scale_x;
-    for (i = 0; i < text_info->length; ++i) {
-        GlyphInfo *g = glyphs + i;
-        g->pos.x *= render_priv->font_scale_x;
-        g->hash_key.advance.x =
-            double_to_d6(device_x - (int) device_x +
-            d6_to_double(g->pos.x & SUBPIXEL_MASK)) & ~SUBPIXEL_ACCURACY;
-        g->hash_key.advance.y =
-            double_to_d6(device_y - (int) device_y +
-            d6_to_double(g->pos.y & SUBPIXEL_MASK)) & ~SUBPIXEL_ACCURACY;
-        get_bitmap_glyph(render_priv, glyphs + i);
-    }
-
-    memset(event_images, 0, sizeof(*event_images));
-    event_images->top = device_y - text_info->lines[0].asc;
-    event_images->height = text_info->height;
-    event_images->left =
-        (device_x + bbox.xMin * render_priv->font_scale_x) + 0.5;
-    event_images->width =
-        (bbox.xMax - bbox.xMin) * render_priv->font_scale_x + 0.5;
-    event_images->detect_collisions = render_priv->state.detect_collisions;
-    event_images->shift_direction = (valign == VALIGN_TOP) ? 1 : -1;
-    event_images->event = event;
-    event_images->imgs = render_text(render_priv, (int) device_x, (int) device_y);
-
-    free_render_context(render_priv);
-
-    return 0;
-}
-
-/**
- * \brief deallocate image list
- * \param img list pointer
- */
-void ass_free_images(ASS_Image *img)
-{
-    while (img) {
-        ASS_Image *next = img->next;
-        free(img);
-        img = next;
-    }
-}
-
-/**
- * \brief Check cache limits and reset cache if they are exceeded
- */
-static void check_cache_limits(ASS_Renderer *priv, CacheStore *cache)
-{
-    if (cache->bitmap_cache->cache_size > cache->bitmap_max_size) {
-        ass_msg(priv->library, MSGL_V,
-                "Hitting hard bitmap cache limit (was: %ld bytes), "
-                "resetting.", (long) cache->bitmap_cache->cache_size);
-        cache->bitmap_cache = ass_bitmap_cache_reset(cache->bitmap_cache);
-        cache->composite_cache = ass_composite_cache_reset(
-            cache->composite_cache);
-        ass_free_images(priv->prev_images_root);
-        priv->prev_images_root = 0;
-    }
-
-    if (cache->glyph_cache->count > cache->glyph_max
-        || cache->glyph_cache->cache_size > cache->bitmap_max_size) {
-        ass_msg(priv->library, MSGL_V,
-            "Hitting hard glyph cache limit (was: %d glyphs, %ld bytes), "
-            "resetting.",
-            cache->glyph_cache->count, (long) cache->glyph_cache->cache_size);
-        cache->glyph_cache = ass_glyph_cache_reset(cache->glyph_cache);
-    }
-}
-
-/**
- * \brief Start a new frame
- */
-static int
-ass_start_frame(ASS_Renderer *render_priv, ASS_Track *track,
-                long long now)
-{
-    ASS_Settings *settings_priv = &render_priv->settings;
-
-    if (!render_priv->settings.frame_width
-        && !render_priv->settings.frame_height)
-        return 1;               // library not initialized
-
-    if (render_priv->library != track->library)
-        return 1;
-
-    if (!render_priv->fontconfig_priv)
-        return 1;
-
-    free_list_clear(render_priv);
-
-    if (track->n_events == 0)
-        return 1;               // nothing to do
-
-    render_priv->track = track;
-    render_priv->time = now;
-
-    ass_lazy_track_init(render_priv);
-
-    render_priv->font_scale = settings_priv->font_size_coeff *
-        render_priv->orig_height / render_priv->track->PlayResY;
-    if (render_priv->track->ScaledBorderAndShadow)
-        render_priv->border_scale =
-            ((double) render_priv->orig_height) /
-            render_priv->track->PlayResY;
-    else
-        render_priv->border_scale = 1.;
-
-    // PAR correction
-    render_priv->font_scale_x = render_priv->settings.aspect /
-                                render_priv->settings.storage_aspect;
-
-    render_priv->prev_images_root = render_priv->images_root;
-    render_priv->images_root = 0;
-
-    check_cache_limits(render_priv, &render_priv->cache);
-
-    return 0;
-}
-
-static int cmp_event_layer(const void *p1, const void *p2)
-{
-    ASS_Event *e1 = ((EventImages *) p1)->event;
-    ASS_Event *e2 = ((EventImages *) p2)->event;
-    if (e1->Layer < e2->Layer)
-        return -1;
-    if (e1->Layer > e2->Layer)
-        return 1;
-    if (e1->ReadOrder < e2->ReadOrder)
-        return -1;
-    if (e1->ReadOrder > e2->ReadOrder)
-        return 1;
-    return 0;
-}
-
-static ASS_RenderPriv *get_render_priv(ASS_Renderer *render_priv,
-                                       ASS_Event *event)
-{
-    if (!event->render_priv)
-        event->render_priv = calloc(1, sizeof(ASS_RenderPriv));
-    if (render_priv->render_id != event->render_priv->render_id) {
-        memset(event->render_priv, 0, sizeof(ASS_RenderPriv));
-        event->render_priv->render_id = render_priv->render_id;
-    }
-
-    return event->render_priv;
-}
-
-static int overlap(Segment *s1, Segment *s2)
-{
-    if (s1->a >= s2->b || s2->a >= s1->b ||
-        s1->ha >= s2->hb || s2->ha >= s1->hb)
-        return 0;
-    return 1;
-}
-
-static int cmp_segment(const void *p1, const void *p2)
-{
-    return ((Segment *) p1)->a - ((Segment *) p2)->a;
-}
-
-static void
-shift_event(ASS_Renderer *render_priv, EventImages *ei, int shift)
-{
-    ASS_Image *cur = ei->imgs;
-    while (cur) {
-        cur->dst_y += shift;
-        // clip top and bottom
-        if (cur->dst_y < 0) {
-            int clip = -cur->dst_y;
-            cur->h -= clip;
-            cur->bitmap += clip * cur->stride;
-            cur->dst_y = 0;
-        }
-        if (cur->dst_y + cur->h >= render_priv->height) {
-            int clip = cur->dst_y + cur->h - render_priv->height;
-            cur->h -= clip;
-        }
-        if (cur->h <= 0) {
-            cur->h = 0;
-            cur->dst_y = 0;
-        }
-        cur = cur->next;
-    }
-    ei->top += shift;
-}
-
-// dir: 1 - move down
-//      -1 - move up
-static int fit_segment(Segment *s, Segment *fixed, int *cnt, int dir)
-{
-    int i;
-    int shift = 0;
-
-    if (dir == 1)               // move down
-        for (i = 0; i < *cnt; ++i) {
-            if (s->b + shift <= fixed[i].a || s->a + shift >= fixed[i].b ||
-                s->hb <= fixed[i].ha || s->ha >= fixed[i].hb)
-                continue;
-            shift = fixed[i].b - s->a;
-    } else                      // dir == -1, move up
-        for (i = *cnt - 1; i >= 0; --i) {
-            if (s->b + shift <= fixed[i].a || s->a + shift >= fixed[i].b ||
-                s->hb <= fixed[i].ha || s->ha >= fixed[i].hb)
-                continue;
-            shift = fixed[i].a - s->b;
-        }
-
-    fixed[*cnt].a = s->a + shift;
-    fixed[*cnt].b = s->b + shift;
-    fixed[*cnt].ha = s->ha;
-    fixed[*cnt].hb = s->hb;
-    (*cnt)++;
-    qsort(fixed, *cnt, sizeof(Segment), cmp_segment);
-
-    return shift;
-}
-
-static void
-fix_collisions(ASS_Renderer *render_priv, EventImages *imgs, int cnt)
-{
-    Segment *used = malloc(cnt * sizeof(*used));
-    int cnt_used = 0;
-    int i, j;
-
-    // fill used[] with fixed events
-    for (i = 0; i < cnt; ++i) {
-        ASS_RenderPriv *priv;
-        if (!imgs[i].detect_collisions)
-            continue;
-        priv = get_render_priv(render_priv, imgs[i].event);
-        if (priv->height > 0) { // it's a fixed event
-            Segment s;
-            s.a = priv->top;
-            s.b = priv->top + priv->height;
-            s.ha = priv->left;
-            s.hb = priv->left + priv->width;
-            if (priv->height != imgs[i].height) {       // no, it's not
-                ass_msg(render_priv->library, MSGL_WARN,
-                        "Event height has changed");
-                priv->top = 0;
-                priv->height = 0;
-                priv->left = 0;
-                priv->width = 0;
-            }
-            for (j = 0; j < cnt_used; ++j)
-                if (overlap(&s, used + j)) {    // no, it's not
-                    priv->top = 0;
-                    priv->height = 0;
-                    priv->left = 0;
-                    priv->width = 0;
-                }
-            if (priv->height > 0) {     // still a fixed event
-                used[cnt_used].a = priv->top;
-                used[cnt_used].b = priv->top + priv->height;
-                used[cnt_used].ha = priv->left;
-                used[cnt_used].hb = priv->left + priv->width;
-                cnt_used++;
-                shift_event(render_priv, imgs + i, priv->top - imgs[i].top);
-            }
-        }
-    }
-    qsort(used, cnt_used, sizeof(Segment), cmp_segment);
-
-    // try to fit other events in free spaces
-    for (i = 0; i < cnt; ++i) {
-        ASS_RenderPriv *priv;
-        if (!imgs[i].detect_collisions)
-            continue;
-        priv = get_render_priv(render_priv, imgs[i].event);
-        if (priv->height == 0) {        // not a fixed event
-            int shift;
-            Segment s;
-            s.a = imgs[i].top;
-            s.b = imgs[i].top + imgs[i].height;
-            s.ha = imgs[i].left;
-            s.hb = imgs[i].left + imgs[i].width;
-            shift = fit_segment(&s, used, &cnt_used, imgs[i].shift_direction);
-            if (shift)
-                shift_event(render_priv, imgs + i, shift);
-            // make it fixed
-            priv->top = imgs[i].top;
-            priv->height = imgs[i].height;
-            priv->left = imgs[i].left;
-            priv->width = imgs[i].width;
-        }
-
-    }
-
-    free(used);
-}
-
-/**
- * \brief compare two images
- * \param i1 first image
- * \param i2 second image
- * \return 0 if identical, 1 if different positions, 2 if different content
- */
-static int ass_image_compare(ASS_Image *i1, ASS_Image *i2)
-{
-    if (i1->w != i2->w)
-        return 2;
-    if (i1->h != i2->h)
-        return 2;
-    if (i1->stride != i2->stride)
-        return 2;
-    if (i1->color != i2->color)
-        return 2;
-    if (i1->bitmap != i2->bitmap)
-        return 2;
-    if (i1->dst_x != i2->dst_x)
-        return 1;
-    if (i1->dst_y != i2->dst_y)
-        return 1;
-    return 0;
-}
-
-/**
- * \brief compare current and previous image list
- * \param priv library handle
- * \return 0 if identical, 1 if different positions, 2 if different content
- */
-static int ass_detect_change(ASS_Renderer *priv)
-{
-    ASS_Image *img, *img2;
-    int diff;
-
-    img = priv->prev_images_root;
-    img2 = priv->images_root;
-    diff = 0;
-    while (img && diff < 2) {
-        ASS_Image *next, *next2;
-        next = img->next;
-        if (img2) {
-            int d = ass_image_compare(img, img2);
-            if (d > diff)
-                diff = d;
-            next2 = img2->next;
-        } else {
-            // previous list is shorter
-            diff = 2;
-            break;
-        }
-        img = next;
-        img2 = next2;
-    }
-
-    // is the previous list longer?
-    if (img2)
-        diff = 2;
-
-    return diff;
-}
-
-/**
- * \brief render a frame
- * \param priv library handle
- * \param track track
- * \param now current video timestamp (ms)
- * \param detect_change a value describing how the new images differ from the previous ones will be written here:
- *        0 if identical, 1 if different positions, 2 if different content.
- *        Can be NULL, in that case no detection is performed.
- */
-ASS_Image *ass_render_frame(ASS_Renderer *priv, ASS_Track *track,
-                            long long now, int *detect_change)
-{
-    int i, cnt, rc;
-    EventImages *last;
-    ASS_Image **tail;
-
-    // init frame
-    rc = ass_start_frame(priv, track, now);
-    if (rc != 0)
-        return 0;
-
-    // render events separately
-    cnt = 0;
-    for (i = 0; i < track->n_events; ++i) {
-        ASS_Event *event = track->events + i;
-        if ((event->Start <= now)
-            && (now < (event->Start + event->Duration))) {
-            if (cnt >= priv->eimg_size) {
-                priv->eimg_size += 100;
-                priv->eimg =
-                    realloc(priv->eimg,
-                            priv->eimg_size * sizeof(EventImages));
-            }
-            rc = ass_render_event(priv, event, priv->eimg + cnt);
-            if (!rc)
-                ++cnt;
-        }
-    }
-
-    // sort by layer
-    qsort(priv->eimg, cnt, sizeof(EventImages), cmp_event_layer);
-
-    // call fix_collisions for each group of events with the same layer
-    last = priv->eimg;
-    for (i = 1; i < cnt; ++i)
-        if (last->event->Layer != priv->eimg[i].event->Layer) {
-            fix_collisions(priv, last, priv->eimg + i - last);
-            last = priv->eimg + i;
-        }
-    if (cnt > 0)
-        fix_collisions(priv, last, priv->eimg + cnt - last);
-
-    // concat lists
-    tail = &priv->images_root;
-    for (i = 0; i < cnt; ++i) {
-        ASS_Image *cur = priv->eimg[i].imgs;
-        while (cur) {
-            *tail = cur;
-            tail = &cur->next;
-            cur = cur->next;
-        }
-    }
-
-    if (detect_change)
-        *detect_change = ass_detect_change(priv);
-
-    // free the previous image list
-    ass_free_images(priv->prev_images_root);
-    priv->prev_images_root = 0;
-
-    return priv->images_root;
-}
diff --git a/aegisub/libass/ass_render.h b/aegisub/libass/ass_render.h
deleted file mode 100644
index 89bffb012..000000000
--- a/aegisub/libass/ass_render.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- * Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef LIBASS_RENDER_H
-#define LIBASS_RENDER_H
-
-#include <inttypes.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_STROKER_H
-#include FT_GLYPH_H
-#include FT_SYNTHESIS_H
-
-#include "ass.h"
-#include "ass_font.h"
-#include "ass_bitmap.h"
-#include "ass_cache.h"
-#include "ass_utils.h"
-#include "ass_fontconfig.h"
-#include "ass_library.h"
-#include "ass_drawing.h"
-
-#define GLYPH_CACHE_MAX 1000
-#define BITMAP_CACHE_MAX_SIZE 30 * 1048576
-
-typedef struct {
-    double xMin;
-    double xMax;
-    double yMin;
-    double yMax;
-} DBBox;
-
-typedef struct {
-    double x;
-    double y;
-} DVector;
-
-typedef struct free_list {
-    void *object;
-    struct free_list *next;
-} FreeList;
-
-typedef struct {
-    int frame_width;
-    int frame_height;
-    double font_size_coeff;     // font size multiplier
-    double line_spacing;        // additional line spacing (in frame pixels)
-    int top_margin;             // height of top margin. Everything except toptitles is shifted down by top_margin.
-    int bottom_margin;          // height of bottom margin. (frame_height - top_margin - bottom_margin) is original video height.
-    int left_margin;
-    int right_margin;
-    int use_margins;            // 0 - place all subtitles inside original frame
-    // 1 - use margins for placing toptitles and subtitles
-    double aspect;              // frame aspect ratio, d_width / d_height.
-    double storage_aspect;      // pixel ratio of the source image
-    ASS_Hinting hinting;
-
-    char *default_font;
-    char *default_family;
-} ASS_Settings;
-
-// a rendered event
-typedef struct {
-    ASS_Image *imgs;
-    int top, height, left, width;
-    int detect_collisions;
-    int shift_direction;
-    ASS_Event *event;
-} EventImages;
-
-typedef enum {
-    EF_NONE = 0,
-    EF_KARAOKE,
-    EF_KARAOKE_KF,
-    EF_KARAOKE_KO
-} Effect;
-
-// describes a glyph
-// GlyphInfo and TextInfo are used for text centering and word-wrapping operations
-typedef struct {
-    unsigned symbol;
-    unsigned skip;              // skip glyph when layouting text
-    FT_Glyph glyph;
-    FT_Glyph outline_glyph;
-    Bitmap *bm;                 // glyph bitmap
-    Bitmap *bm_o;               // outline bitmap
-    Bitmap *bm_s;               // shadow bitmap
-    FT_BBox bbox;
-    FT_Vector pos;
-    char linebreak;             // the first (leading) glyph of some line ?
-    uint32_t c[4];              // colors
-    FT_Vector advance;          // 26.6
-    Effect effect_type;
-    int effect_timing;          // time duration of current karaoke word
-    // after process_karaoke_effects: distance in pixels from the glyph origin.
-    // part of the glyph to the left of it is displayed in a different color.
-    int effect_skip_timing;     // delay after the end of last karaoke word
-    int asc, desc;              // font max ascender and descender
-    int be;                     // blur edges
-    double blur;                // gaussian blur
-    double shadow_x;
-    double shadow_y;
-    double frx, fry, frz;       // rotation
-    double fax, fay;            // text shearing
-
-    BitmapHashKey hash_key;
-} GlyphInfo;
-
-typedef struct {
-    double asc, desc;
-} LineInfo;
-
-typedef struct {
-    GlyphInfo *glyphs;
-    int length;
-    LineInfo *lines;
-    int n_lines;
-    double height;
-    int max_glyphs;
-    int max_lines;
-} TextInfo;
-
-// Renderer state.
-// Values like current font face, color, screen position, clipping and so on are stored here.
-typedef struct {
-    ASS_Event *event;
-    ASS_Style *style;
-
-    ASS_Font *font;
-    char *font_path;
-    double font_size;
-    int flags;                  // decoration flags (underline/strike-through)
-
-    FT_Stroker stroker;
-    int alignment;              // alignment overrides go here; if zero, style value will be used
-    double frx, fry, frz;
-    double fax, fay;            // text shearing
-    enum {
-        EVENT_NORMAL,           // "normal" top-, sub- or mid- title
-        EVENT_POSITIONED,       // happens after pos(,), margins are ignored
-        EVENT_HSCROLL,          // "Banner" transition effect, text_width is unlimited
-        EVENT_VSCROLL           // "Scroll up", "Scroll down" transition effects
-    } evt_type;
-    double pos_x, pos_y;        // position
-    double org_x, org_y;        // origin
-    char have_origin;           // origin is explicitly defined; if 0, get_base_point() is used
-    double scale_x, scale_y;
-    double hspacing;            // distance between letters, in pixels
-    double border_x;            // outline width
-    double border_y;
-    uint32_t c[4];              // colors(Primary, Secondary, so on) in RGBA
-    int clip_x0, clip_y0, clip_x1, clip_y1;
-    char clip_mode;             // 1 = iclip
-    char detect_collisions;
-    uint32_t fade;              // alpha from \fad
-    char be;                    // blur edges
-    double blur;                // gaussian blur
-    double shadow_x;
-    double shadow_y;
-    int drawing_mode;           // not implemented; when != 0 text is discarded, except for style override tags
-    ASS_Drawing *drawing;       // current drawing
-    ASS_Drawing *clip_drawing;  // clip vector
-    int clip_drawing_mode;      // 0 = regular clip, 1 = inverse clip
-
-    Effect effect_type;
-    int effect_timing;
-    int effect_skip_timing;
-
-    enum {
-        SCROLL_LR,              // left-to-right
-        SCROLL_RL,
-        SCROLL_TB,              // top-to-bottom
-        SCROLL_BT
-    } scroll_direction;         // for EVENT_HSCROLL, EVENT_VSCROLL
-    int scroll_shift;
-
-    // face properties
-    char *family;
-    unsigned bold;
-    unsigned italic;
-    int treat_family_as_pattern;
-    int wrap_style;
-} RenderContext;
-
-typedef struct {
-    Hashmap *font_cache;
-    Hashmap *glyph_cache;
-    Hashmap *bitmap_cache;
-    Hashmap *composite_cache;
-    size_t glyph_max;
-    size_t bitmap_max_size;
-} CacheStore;
-
-struct ass_renderer {
-    ASS_Library *library;
-    FT_Library ftlibrary;
-    FCInstance *fontconfig_priv;
-    ASS_Settings settings;
-    int render_id;
-    ASS_SynthPriv *synth_priv;
-
-    ASS_Image *images_root;     // rendering result is stored here
-    ASS_Image *prev_images_root;
-
-    EventImages *eimg;          // temporary buffer for sorting rendered events
-    int eimg_size;              // allocated buffer size
-
-    // frame-global data
-    int width, height;          // screen dimensions
-    int orig_height;            // frame height ( = screen height - margins )
-    int orig_width;             // frame width ( = screen width - margins )
-    int orig_height_nocrop;     // frame height ( = screen height - margins + cropheight)
-    int orig_width_nocrop;      // frame width ( = screen width - margins + cropwidth)
-    ASS_Track *track;
-    long long time;             // frame's timestamp, ms
-    double font_scale;
-    double font_scale_x;        // x scale applied to all glyphs to preserve text aspect ratio
-    double border_scale;
-
-    RenderContext state;
-    TextInfo text_info;
-    CacheStore cache;
-
-    FreeList *free_head;
-    FreeList *free_tail;
-};
-
-typedef struct render_priv {
-    int top, height, left, width;
-    int render_id;
-} RenderPriv;
-
-typedef struct {
-    int x0;
-    int y0;
-    int x1;
-    int y1;
-} Rect;
-
-typedef struct {
-    int a, b;                   // top and height
-    int ha, hb;                 // left and width
-} Segment;
-
-void reset_render_context(ASS_Renderer *render_priv);
-void ass_free_images(ASS_Image *img);
-
-#endif /* LIBASS_RENDER_H */
diff --git a/aegisub/libass/ass_render_api.c b/aegisub/libass/ass_render_api.c
deleted file mode 100644
index 65cfa58d0..000000000
--- a/aegisub/libass/ass_render_api.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- * Copyright (C) 2010 Grigori Goronzy <greg@geekmind.org>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-#include "ass_render.h"
-
-static void ass_reconfigure(ASS_Renderer *priv)
-{
-    ASS_Settings *settings = &priv->settings;
-
-    priv->render_id++;
-    priv->cache.glyph_cache =
-        ass_glyph_cache_reset(priv->cache.glyph_cache);
-    priv->cache.bitmap_cache =
-        ass_bitmap_cache_reset(priv->cache.bitmap_cache);
-    priv->cache.composite_cache =
-        ass_composite_cache_reset(priv->cache.composite_cache);
-    ass_free_images(priv->prev_images_root);
-    priv->prev_images_root = 0;
-
-    priv->width = settings->frame_width;
-    priv->height = settings->frame_height;
-    priv->orig_width = settings->frame_width - settings->left_margin -
-        settings->right_margin;
-    priv->orig_height = settings->frame_height - settings->top_margin -
-        settings->bottom_margin;
-    priv->orig_width_nocrop =
-        settings->frame_width - FFMAX(settings->left_margin, 0) -
-        FFMAX(settings->right_margin, 0);
-    priv->orig_height_nocrop =
-        settings->frame_height - FFMAX(settings->top_margin, 0) -
-        FFMAX(settings->bottom_margin, 0);
-}
-
-void ass_set_frame_size(ASS_Renderer *priv, int w, int h)
-{
-    if (priv->settings.frame_width != w || priv->settings.frame_height != h) {
-        priv->settings.frame_width = w;
-        priv->settings.frame_height = h;
-        if (priv->settings.aspect == 0.) {
-            priv->settings.aspect = ((double) w) / h;
-            priv->settings.storage_aspect = ((double) w) / h;
-        }
-        ass_reconfigure(priv);
-    }
-}
-
-void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r)
-{
-    if (priv->settings.left_margin != l || priv->settings.right_margin != r ||
-        priv->settings.top_margin != t || priv->settings.bottom_margin != b) {
-        priv->settings.left_margin = l;
-        priv->settings.right_margin = r;
-        priv->settings.top_margin = t;
-        priv->settings.bottom_margin = b;
-        ass_reconfigure(priv);
-    }
-}
-
-void ass_set_use_margins(ASS_Renderer *priv, int use)
-{
-    priv->settings.use_margins = use;
-}
-
-void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar)
-{
-    if (priv->settings.aspect != dar || priv->settings.storage_aspect != sar) {
-        priv->settings.aspect = dar;
-        priv->settings.storage_aspect = sar;
-        ass_reconfigure(priv);
-    }
-}
-
-void ass_set_font_scale(ASS_Renderer *priv, double font_scale)
-{
-    if (priv->settings.font_size_coeff != font_scale) {
-        priv->settings.font_size_coeff = font_scale;
-        ass_reconfigure(priv);
-    }
-}
-
-void ass_set_hinting(ASS_Renderer *priv, ASS_Hinting ht)
-{
-    if (priv->settings.hinting != ht) {
-        priv->settings.hinting = ht;
-        ass_reconfigure(priv);
-    }
-}
-
-void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing)
-{
-    priv->settings.line_spacing = line_spacing;
-}
-
-void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
-                   const char *default_family, int fc, const char *config,
-                   int update)
-{
-    free(priv->settings.default_font);
-    free(priv->settings.default_family);
-    priv->settings.default_font = default_font ? strdup(default_font) : 0;
-    priv->settings.default_family =
-        default_family ? strdup(default_family) : 0;
-
-    if (priv->fontconfig_priv)
-        fontconfig_done(priv->fontconfig_priv);
-    priv->fontconfig_priv =
-        fontconfig_init(priv->library, priv->ftlibrary, default_family,
-                        default_font, fc, config, update);
-}
-
-int ass_fonts_update(ASS_Renderer *render_priv)
-{
-    return fontconfig_update(render_priv->fontconfig_priv);
-}
-
-void ass_set_cache_limits(ASS_Renderer *render_priv, int glyph_max,
-                          int bitmap_max)
-{
-    render_priv->cache.glyph_max = glyph_max ? glyph_max : GLYPH_CACHE_MAX;
-    render_priv->cache.bitmap_max_size = bitmap_max ? 1048576 * bitmap_max :
-                                         BITMAP_CACHE_MAX_SIZE;
-}
diff --git a/aegisub/libass/ass_strtod.c b/aegisub/libass/ass_strtod.c
deleted file mode 100644
index b26cdd205..000000000
--- a/aegisub/libass/ass_strtod.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (c) 1988-1993 The Regents of the University of California.
- * Copyright (c) 1994 Sun Microsystems, Inc.
- *
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies.  The University of California
- * makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without
- * express or implied warranty.
- *
- */
-
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-
-const
-static int maxExponent = 511;   /* Largest possible base 10 exponent.  Any
-                                 * exponent larger than this will already
-                                 * produce underflow or overflow, so there's
-                                 * no need to worry about additional digits.
-                                 */
-
-const
-static double powersOf10[] = {  /* Table giving binary powers of 10.  Entry */
-    10.,                        /* is 10^2^i.  Used to convert decimal */
-    100.,                       /* exponents into floating-point numbers. */
-    1.0e4,
-    1.0e8,
-    1.0e16,
-    1.0e32,
-    1.0e64,
-    1.0e128,
-    1.0e256
-};
-
-/*
- *----------------------------------------------------------------------
- *
- * strtod --
- *
- * This procedure converts a floating-point number from an ASCII
- * decimal representation to internal double-precision format.
- *
- * Results:
- * The return value is the double-precision floating-point
- * representation of the characters in string.  If endPtr isn't
- * NULL, then *endPtr is filled in with the address of the
- * next character after the last one that was part of the
- * floating-point number.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-double
-ass_strtod(string, endPtr)
-    const char *string;     /* A decimal ASCII floating-point number,
-                             * optionally preceded by white space.
-                             * Must have form "-I.FE-X", where I is the
-                             * integer part of the mantissa, F is the
-                             * fractional part of the mantissa, and X
-                             * is the exponent.  Either of the signs
-                             * may be "+", "-", or omitted.  Either I
-                             * or F may be omitted, or both.  The decimal
-                             * point isn't necessary unless F is present.
-                             * The "E" may actually be an "e".  E and X
-                             * may both be omitted (but not just one).
-                             */
-    char **endPtr;          /* If non-NULL, store terminating character's
-                             * address here. */
-{
-    int sign, expSign = 0;
-    double fraction, dblExp, *d;
-    register const char *p;
-    register int c;
-    int exp = 0;            /* Exponent read from "EX" field. */
-    int fracExp = 0;        /* Exponent that derives from the fractional
-                             * part.  Under normal circumstatnces, it is
-                             * the negative of the number of digits in F.
-                             * However, if I is very long, the last digits
-                             * of I get dropped (otherwise a long I with a
-                             * large negative exponent could cause an
-                             * unnecessary overflow on I alone).  In this
-                             * case, fracExp is incremented one for each
-                             * dropped digit. */
-    int mantSize;       /* Number of digits in mantissa. */
-    int decPt;          /* Number of mantissa digits BEFORE decimal
-                         * point. */
-    const char *pExp;       /* Temporarily holds location of exponent
-                             * in string. */
-
-    /*
-     * Strip off leading blanks and check for a sign.
-     */
-
-    p = string;
-    while (isascii(*p) && isspace(*p)) {
-        p += 1;
-    }
-    if (*p == '-') {
-        sign = 1;
-        p += 1;
-    } else {
-        if (*p == '+') {
-            p += 1;
-        }
-        sign = 0;
-    }
-
-    /*
-     * Count the number of digits in the mantissa (including the decimal
-     * point), and also locate the decimal point.
-     */
-
-    decPt = -1;
-    for (mantSize = 0; ; mantSize += 1)
-    {
-        c = *p;
-        if (!isascii(*p) || !isdigit(c)) {
-            if ((c != '.') || (decPt >= 0)) {
-                break;
-            }
-            decPt = mantSize;
-        }
-        p += 1;
-    }
-
-    /*
-     * Now suck up the digits in the mantissa.  Use two integers to
-     * collect 9 digits each (this is faster than using floating-point).
-     * If the mantissa has more than 18 digits, ignore the extras, since
-     * they can't affect the value anyway.
-     */
-
-    pExp  = p;
-    p -= mantSize;
-    if (decPt < 0) {
-        decPt = mantSize;
-    } else {
-        mantSize -= 1;      /* One of the digits was the point. */
-    }
-    if (mantSize > 18) {
-        fracExp = decPt - 18;
-        mantSize = 18;
-    } else {
-        fracExp = decPt - mantSize;
-    }
-    if (mantSize == 0) {
-        fraction = 0.0;
-        p = string;
-        goto done;
-    } else {
-        int frac1, frac2;
-        frac1 = 0;
-        for ( ; mantSize > 9; mantSize -= 1)
-        {
-            c = *p;
-            p += 1;
-            if (c == '.') {
-                c = *p;
-                p += 1;
-            }
-            frac1 = 10*frac1 + (c - '0');
-        }
-        frac2 = 0;
-        for (; mantSize > 0; mantSize -= 1)
-        {
-            c = *p;
-            p += 1;
-            if (c == '.') {
-                c = *p;
-                p += 1;
-            }
-            frac2 = 10*frac2 + (c - '0');
-        }
-        fraction = (1.0e9 * frac1) + frac2;
-    }
-
-    /*
-     * Skim off the exponent.
-     */
-
-    p = pExp;
-    if ((*p == 'E') || (*p == 'e')) {
-        p += 1;
-        if (*p == '-') {
-            expSign = 1;
-            p += 1;
-        } else {
-            if (*p == '+') {
-                p += 1;
-            }
-            expSign = 0;
-        }
-        while (isascii(*p) && isdigit(*p)) {
-            exp = exp * 10 + (*p - '0');
-            p += 1;
-        }
-    }
-    if (expSign) {
-        exp = fracExp - exp;
-    } else {
-        exp = fracExp + exp;
-    }
-
-    /*
-     * Generate a floating-point number that represents the exponent.
-     * Do this by processing the exponent one bit at a time to combine
-     * many powers of 2 of 10. Then combine the exponent with the
-     * fraction.
-     */
-
-    if (exp < 0) {
-        expSign = 1;
-        exp = -exp;
-    } else {
-        expSign = 0;
-    }
-    if (exp > maxExponent) {
-        exp = maxExponent;
-        errno = ERANGE;
-    }
-    dblExp = 1.0;
-    for (d = (double *) powersOf10; exp != 0; exp >>= 1, d += 1) {
-        if (exp & 01) {
-            dblExp *= *d;
-        }
-    }
-    if (expSign) {
-        fraction /= dblExp;
-    } else {
-        fraction *= dblExp;
-    }
-
-done:
-    if (endPtr != NULL) {
-        *endPtr = (char *) p;
-    }
-
-    if (sign) {
-        return -fraction;
-    }
-    return fraction;
-}
diff --git a/aegisub/libass/ass_types.h b/aegisub/libass/ass_types.h
deleted file mode 100644
index 6a6f1ae86..000000000
--- a/aegisub/libass/ass_types.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef LIBASS_TYPES_H
-#define LIBASS_TYPES_H
-
-#include <stdint.h>
-
-#define VALIGN_SUB 0
-#define VALIGN_CENTER 8
-#define VALIGN_TOP 4
-#define HALIGN_LEFT 1
-#define HALIGN_CENTER 2
-#define HALIGN_RIGHT 3
-
-/* Opaque objects internally used by libass.  Contents are private. */
-typedef struct ass_renderer ASS_Renderer;
-typedef struct render_priv ASS_RenderPriv;
-typedef struct parser_priv ASS_ParserPriv;
-typedef struct ass_library ASS_Library;
-
-/* ASS Style: line */
-typedef struct ass_style {
-    char *Name;
-    char *FontName;
-    double FontSize;
-    uint32_t PrimaryColour;
-    uint32_t SecondaryColour;
-    uint32_t OutlineColour;
-    uint32_t BackColour;
-    int Bold;
-    int Italic;
-    int Underline;
-    int StrikeOut;
-    double ScaleX;
-    double ScaleY;
-    double Spacing;
-    int Angle;
-    int BorderStyle;
-    double Outline;
-    double Shadow;
-    int Alignment;
-    int MarginL;
-    int MarginR;
-    int MarginV;
-    int Encoding;
-    int treat_fontname_as_pattern;
-} ASS_Style;
-
-/*
- * ASS_Event corresponds to a single Dialogue line;
- * text is stored as-is, style overrides will be parsed later.
- */
-typedef struct ass_event {
-    long long Start;            // ms
-    long long Duration;         // ms
-
-    int ReadOrder;
-    int Layer;
-    int Style;
-    char *Name;
-    int MarginL;
-    int MarginR;
-    int MarginV;
-    char *Effect;
-    char *Text;
-
-    ASS_RenderPriv *render_priv;
-} ASS_Event;
-
-/*
- * ass track represent either an external script or a matroska subtitle stream
- * (no real difference between them); it can be used in rendering after the
- * headers are parsed (i.e. events format line read).
- */
-typedef struct ass_track {
-    int n_styles;           // amount used
-    int max_styles;         // amount allocated
-    int n_events;
-    int max_events;
-    ASS_Style *styles;    // array of styles, max_styles length, n_styles used
-    ASS_Event *events;    // the same as styles
-
-    char *style_format;     // style format line (everything after "Format: ")
-    char *event_format;     // event format line
-
-    enum {
-        TRACK_TYPE_UNKNOWN = 0,
-        TRACK_TYPE_ASS,
-        TRACK_TYPE_SSA
-    } track_type;
-
-    // Script header fields
-    int PlayResX;
-    int PlayResY;
-    double Timer;
-    int WrapStyle;
-    int ScaledBorderAndShadow;
-    int Kerning;
-
-    int default_style;      // index of default style
-    char *name;             // file name in case of external subs, 0 for streams
-
-    ASS_Library *library;
-    ASS_ParserPriv *parser_priv;
-} ASS_Track;
-
-#endif /* LIBASS_TYPES_H */
diff --git a/aegisub/libass/ass_utils.c b/aegisub/libass/ass_utils.c
deleted file mode 100644
index 4c9d4bcc6..000000000
--- a/aegisub/libass/ass_utils.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <inttypes.h>
-#include <ft2build.h>
-#include FT_GLYPH_H
-#include <strings.h>
-
-#include "ass_library.h"
-#include "ass.h"
-#include "ass_utils.h"
-
-int mystrtoi(char **p, int *res)
-{
-    double temp_res;
-    char *start = *p;
-    temp_res = ass_strtod(*p, p);
-    *res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
-    if (*p != start)
-        return 1;
-    else
-        return 0;
-}
-
-int mystrtoll(char **p, long long *res)
-{
-    double temp_res;
-    char *start = *p;
-    temp_res = ass_strtod(*p, p);
-    *res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
-    if (*p != start)
-        return 1;
-    else
-        return 0;
-}
-
-int mystrtou32(char **p, int base, uint32_t *res)
-{
-    char *start = *p;
-    *res = strtoll(*p, p, base);
-    if (*p != start)
-        return 1;
-    else
-        return 0;
-}
-
-int mystrtod(char **p, double *res)
-{
-    char *start = *p;
-    *res = ass_strtod(*p, p);
-    if (*p != start)
-        return 1;
-    else
-        return 0;
-}
-
-int strtocolor(ASS_Library *library, char **q, uint32_t *res, int hex)
-{
-    uint32_t color = 0;
-    int result;
-    char *p = *q;
-    int base = hex ? 16 : 10;
-
-    if (*p == '&')
-        ++p;
-    else
-        ass_msg(library, MSGL_DBG2, "suspicious color format: \"%s\"\n", p);
-
-    if (*p == 'H' || *p == 'h') {
-        ++p;
-        result = mystrtou32(&p, 16, &color);
-    } else {
-        result = mystrtou32(&p, base, &color);
-    }
-
-    {
-        unsigned char *tmp = (unsigned char *) (&color);
-        unsigned char b;
-        b = tmp[0];
-        tmp[0] = tmp[3];
-        tmp[3] = b;
-        b = tmp[1];
-        tmp[1] = tmp[2];
-        tmp[2] = b;
-    }
-    if (*p == '&')
-        ++p;
-    *q = p;
-
-    *res = color;
-    return result;
-}
-
-// Return a boolean value for a string
-char parse_bool(char *str)
-{
-    while (*str == ' ' || *str == '\t')
-        str++;
-    if (!strncasecmp(str, "yes", 3))
-        return 1;
-    else if (strtol(str, NULL, 10) > 0)
-        return 1;
-    return 0;
-}
-
-void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...)
-{
-    va_list va;
-    va_start(va, fmt);
-    priv->msg_callback(lvl, fmt, va, priv->msg_callback_data);
-    va_end(va);
-}
-
-unsigned ass_utf8_get_char(char **str)
-{
-    uint8_t *strp = (uint8_t *) * str;
-    unsigned c = *strp++;
-    unsigned mask = 0x80;
-    int len = -1;
-    while (c & mask) {
-        mask >>= 1;
-        len++;
-    }
-    if (len <= 0 || len > 4)
-        goto no_utf8;
-    c &= mask - 1;
-    while ((*strp & 0xc0) == 0x80) {
-        if (len-- <= 0)
-            goto no_utf8;
-        c = (c << 6) | (*strp++ & 0x3f);
-    }
-    if (len)
-        goto no_utf8;
-    *str = (char *) strp;
-    return c;
-
-  no_utf8:
-    strp = (uint8_t *) * str;
-    c = *strp++;
-    *str = (char *) strp;
-    return c;
-}
-
-#ifdef CONFIG_ENCA
-void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer,
-                          int buflen, char *preferred_language,
-                          char *fallback)
-{
-    const char **languages;
-    size_t langcnt;
-    EncaAnalyser analyser;
-    EncaEncoding encoding;
-    char *detected_sub_cp = NULL;
-    int i;
-
-    languages = enca_get_languages(&langcnt);
-    ass_msg(library, MSGL_V, "ENCA supported languages");
-    for (i = 0; i < langcnt; i++) {
-        ass_msg(library, MSGL_V, "lang %s", languages[i]);
-    }
-
-    for (i = 0; i < langcnt; i++) {
-        const char *tmp;
-
-        if (strcasecmp(languages[i], preferred_language) != 0)
-            continue;
-        analyser = enca_analyser_alloc(languages[i]);
-        encoding = enca_analyse_const(analyser, buffer, buflen);
-        tmp = enca_charset_name(encoding.charset, ENCA_NAME_STYLE_ICONV);
-        if (tmp && encoding.charset != ENCA_CS_UNKNOWN) {
-            detected_sub_cp = strdup(tmp);
-            ass_msg(library, MSGL_INFO, "ENCA detected charset: %s", tmp);
-        }
-        enca_analyser_free(analyser);
-    }
-
-    free(languages);
-
-    if (!detected_sub_cp) {
-        detected_sub_cp = strdup(fallback);
-        ass_msg(library, MSGL_INFO,
-               "ENCA detection failed: fallback to %s", fallback);
-    }
-
-    return detected_sub_cp;
-}
-#endif
diff --git a/aegisub/libass/ass_utils.h b/aegisub/libass/ass_utils.h
deleted file mode 100644
index 327bb79cf..000000000
--- a/aegisub/libass/ass_utils.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef LIBASS_UTILS_H
-#define LIBASS_UTILS_H
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#ifdef CONFIG_ENCA
-#include <enca.h>
-#endif
-
-#include "ass.h"
-
-#define MSGL_FATAL 0
-#define MSGL_ERR 1
-#define MSGL_WARN 2
-#define MSGL_INFO 4
-#define MSGL_V 6
-#define MSGL_DBG2 7
-
-#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
-#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
-#define FFMINMAX(c,a,b) FFMIN(FFMAX(c, a), b)
-
-int mystrtoi(char **p, int *res);
-int mystrtoll(char **p, long long *res);
-int mystrtou32(char **p, int base, uint32_t *res);
-int mystrtod(char **p, double *res);
-int strtocolor(ASS_Library *library, char **q, uint32_t *res, int hex);
-char parse_bool(char *str);
-unsigned ass_utf8_get_char(char **str);
-void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...);
-#ifdef CONFIG_ENCA
-void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer,
-                          int buflen, char *preferred_language,
-                          char *fallback);
-#endif
-
-/* defined in ass_strtod.c */
-double ass_strtod(const char *string, char **endPtr);
-
-static inline int d6_to_int(int x)
-{
-    return (x + 32) >> 6;
-}
-static inline int d16_to_int(int x)
-{
-    return (x + 32768) >> 16;
-}
-static inline int int_to_d6(int x)
-{
-    return x << 6;
-}
-static inline int int_to_d16(int x)
-{
-    return x << 16;
-}
-static inline int d16_to_d6(int x)
-{
-    return (x + 512) >> 10;
-}
-static inline int d6_to_d16(int x)
-{
-    return x << 10;
-}
-static inline double d6_to_double(int x)
-{
-    return x / 64.;
-}
-static inline int double_to_d6(double x)
-{
-    return (int) (x * 64);
-}
-static inline double d16_to_double(int x)
-{
-    return ((double) x) / 0x10000;
-}
-static inline int double_to_d16(double x)
-{
-    return (int) (x * 0x10000);
-}
-static inline double d22_to_double(int x)
-{
-    return ((double) x) / 0x400000;
-}
-static inline int double_to_d22(double x)
-{
-    return (int) (x * 0x400000);
-}
-
-// Calculate cache key for a rotational angle in degrees
-static inline int rot_key(double a)
-{
-    const int m = double_to_d22(360.0);
-    return double_to_d22(a) % m;
-}
-
-#define FNV1_32A_INIT (unsigned)0x811c9dc5
-
-static inline unsigned fnv_32a_buf(void *buf, size_t len, unsigned hval)
-{
-    unsigned char *bp = buf;
-    unsigned char *be = bp + len;
-    while (bp < be) {
-        hval ^= (unsigned) *bp++;
-        hval +=
-            (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) +
-            (hval << 24);
-    }
-    return hval;
-}
-static inline unsigned fnv_32a_str(char *str, unsigned hval)
-{
-    unsigned char *s = (unsigned char *) str;
-    while (*s) {
-        hval ^= (unsigned) *s++;
-        hval +=
-            (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) +
-            (hval << 24);
-    }
-    return hval;
-}
-
-#endif                          /* LIBASS_UTILS_H */
diff --git a/aegisub/libass/config.h b/aegisub/libass/config.h
deleted file mode 100644
index d6bb4217e..000000000
--- a/aegisub/libass/config.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifdef _MSC_VER
-#define CONFIG_FONTCONFIG 1
-#define CONFIG_ICONV 1
-
-#define inline __inline
-
-#define strtoll(p, e, b) _strtoi64(p, e, b)
-
-#define M_PI 3.1415926535897932384626433832795
-
-#pragma warning(disable : 4996)
-#endif
diff --git a/aegisub/libass/help_mp.h b/aegisub/libass/help_mp.h
deleted file mode 100644
index 4e235f4c3..000000000
--- a/aegisub/libass/help_mp.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef __LIBASS_HELP_MP_H__
-#define __LIBASS_HELP_MP_H__
-#define MSGTR_LIBASS_FT_Glyph_To_BitmapError "[ass] FT_Glyph_To_Bitmap error %d \n"
-#define MSGTR_LIBASS_UnsupportedPixelMode "[ass] Unsupported pixel mode: %d\n"
-#define MSGTR_LIBASS_GlyphBBoxTooLarge "[ass] Glyph bounding box too large: %dx%dpx\n"
-#define MSGTR_LIBASS_NoStyleNamedXFoundUsingY "[ass] [%p] Warning: no style named '%s' found, using '%s'\n"
-#define MSGTR_LIBASS_BadTimestamp "[ass] bad timestamp\n"
-#define MSGTR_LIBASS_BadEncodedDataSize "[ass] bad encoded data size\n"
-#define MSGTR_LIBASS_FontLineTooLong "[ass] Font line too long: %d, %s\n"
-#define MSGTR_LIBASS_EventFormatHeaderMissing "[ass] Event format header missing\n"
-#define MSGTR_LIBASS_ErrorOpeningIconvDescriptor "[ass] error opening iconv descriptor.\n"
-#define MSGTR_LIBASS_ErrorRecodingFile "[ass] error recoding file.\n"
-#define MSGTR_LIBASS_FopenFailed "[ass] ass_read_file(%s): fopen failed\n"
-#define MSGTR_LIBASS_FseekFailed "[ass] ass_read_file(%s): fseek failed\n"
-#define MSGTR_LIBASS_RefusingToLoadSubtitlesLargerThan10M "[ass] ass_read_file(%s): Refusing to load subtitles larger than 10M\n"
-#define MSGTR_LIBASS_ReadFailed "Read failed, %d: %s\n"
-#define MSGTR_LIBASS_AddedSubtitleFileMemory "[ass] Added subtitle file: <memory> (%d styles, %d events)\n"
-#define MSGTR_LIBASS_AddedSubtitleFileFname "[ass] Added subtitle file: %s (%d styles, %d events)\n"
-#define MSGTR_LIBASS_FailedToCreateDirectory "[ass] Failed to create directory %s\n"
-#define MSGTR_LIBASS_NotADirectory "[ass] Not a directory: %s\n"
-#define MSGTR_LIBASS_TooManyFonts "[ass] Too many fonts\n"
-#define MSGTR_LIBASS_ErrorOpeningFont "[ass] Error opening font: %s, %d\n"
-#define MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne "[ass] fontconfig: Selected font is not the requested one: '%s' != '%s'\n"
-#define MSGTR_LIBASS_UsingDefaultFontFamily "[ass] fontconfig_select: Using default font family: (%s, %d, %d) -> %s, %d\n"
-#define MSGTR_LIBASS_UsingDefaultFont "[ass] fontconfig_select: Using default font: (%s, %d, %d) -> %s, %d\n"
-#define MSGTR_LIBASS_UsingArialFontFamily "[ass] fontconfig_select: Using 'Arial' font family: (%s, %d, %d) -> %s, %d\n"
-#define MSGTR_LIBASS_FcInitLoadConfigAndFontsFailed "[ass] FcInitLoadConfigAndFonts failed.\n"
-#define MSGTR_LIBASS_UpdatingFontCache "[ass] Updating font cache.\n"
-#define MSGTR_LIBASS_BetaVersionsOfFontconfigAreNotSupported "[ass] Beta versions of fontconfig are not supported.\n[ass] Update before reporting any bugs.\n"
-#define MSGTR_LIBASS_FcStrSetAddFailed "[ass] FcStrSetAdd failed.\n"
-#define MSGTR_LIBASS_FcDirScanFailed "[ass] FcDirScan failed.\n"
-#define MSGTR_LIBASS_FcDirSave "[ass] FcDirSave failed.\n"
-#define MSGTR_LIBASS_FcConfigAppFontAddDirFailed "[ass] FcConfigAppFontAddDir failed\n"
-#define MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed "[ass] Fontconfig disabled, only default font will be used.\n"
-#define MSGTR_LIBASS_FunctionCallFailed "[ass] %s failed\n"
-#define MSGTR_LIBASS_NeitherPlayResXNorPlayResYDefined "[ass] Neither PlayResX nor PlayResY defined. Assuming 384x288.\n"
-#define MSGTR_LIBASS_PlayResYUndefinedSettingY "[ass] PlayResY undefined, setting %d.\n"
-#define MSGTR_LIBASS_PlayResXUndefinedSettingX "[ass] PlayResX undefined, setting %d.\n"
-#define MSGTR_LIBASS_FT_Init_FreeTypeFailed "[ass] FT_Init_FreeType failed.\n"
-#define MSGTR_LIBASS_Init "[ass] Init\n"
-#define MSGTR_LIBASS_InitFailed "[ass] Init failed.\n"
-#define MSGTR_LIBASS_BadCommand "[ass] Bad command: %c%c\n"
-#define MSGTR_LIBASS_ErrorLoadingGlyph  "[ass] Error loading glyph.\n"
-#define MSGTR_LIBASS_FT_Glyph_Stroke_Error "[ass] FT_Glyph_Stroke error %d \n"
-#define MSGTR_LIBASS_UnknownEffectType_InternalError "[ass] Unknown effect type (internal error)\n"
-#define MSGTR_LIBASS_NoStyleFound "[ass] No style found!\n"
-#define MSGTR_LIBASS_EmptyEvent "[ass] Empty event!\n"
-#define MSGTR_LIBASS_MAX_GLYPHS_Reached "[ass] MAX_GLYPHS reached: event %d, start = %llu, duration = %llu\n Text = %s\n"
-#define MSGTR_LIBASS_EventHeightHasChanged "[ass] Warning! Event height has changed!  \n"
-#define MSGTR_LIBASS_GlyphNotFoundReselectingFont "[ass] Glyph 0x%X not found, selecting one more font for (%s, %d, %d)\n"
-#define MSGTR_LIBASS_GlyphNotFound "[ass] Glyph 0x%X not found in font for (%s, %d, %d)\n"
-#define MSGTR_LIBASS_ErrorOpeningMemoryFont "[ass] Error opening memory font: %s\n"
-#define MSGTR_LIBASS_NoCharmaps "[ass] font face with no charmaps\n"
-#define MSGTR_LIBASS_NoCharmapAutodetected "[ass] no charmap autodetected, trying the first one\n"
-#endif
diff --git a/aegisub/libass/msvc/enca.h b/aegisub/libass/msvc/enca.h
deleted file mode 100644
index cfb5f550c..000000000
--- a/aegisub/libass/msvc/enca.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/* @(#) $Id: enca.h,v 1.11 2005/02/27 12:08:55 yeti Exp $ */
-/* This header file is in the public domain. */
-#ifndef ENCA_H
-#define ENCA_H
-
-#include <stdlib.h>
-/* According to autoconf stdlib may not be enough for size_t */
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/* Enumerated types */
-
-typedef enum { /*< flags >*/
-  ENCA_SURFACE_EOL_CR    = 1 << 0,
-  ENCA_SURFACE_EOL_LF    = 1 << 1,
-  ENCA_SURFACE_EOL_CRLF  = 1 << 2,
-  ENCA_SURFACE_EOL_MIX   = 1 << 3,
-  ENCA_SURFACE_EOL_BIN   = 1 << 4,
-  ENCA_SURFACE_MASK_EOL  = (ENCA_SURFACE_EOL_CR
-                            | ENCA_SURFACE_EOL_LF
-                            | ENCA_SURFACE_EOL_CRLF
-                            | ENCA_SURFACE_EOL_MIX
-                            | ENCA_SURFACE_EOL_BIN),
-  ENCA_SURFACE_PERM_21    = 1 << 5,
-  ENCA_SURFACE_PERM_4321  = 1 << 6,
-  ENCA_SURFACE_PERM_MIX   = 1 << 7,
-  ENCA_SURFACE_MASK_PERM  = (ENCA_SURFACE_PERM_21
-                             | ENCA_SURFACE_PERM_4321
-                             | ENCA_SURFACE_PERM_MIX),
-  ENCA_SURFACE_QP        = 1 << 8,
-  ENCA_SURFACE_REMOVE    = 1 << 13,
-  ENCA_SURFACE_UNKNOWN   = 1 << 14,
-  ENCA_SURFACE_MASK_ALL  = (ENCA_SURFACE_MASK_EOL
-                            | ENCA_SURFACE_MASK_PERM
-                            | ENCA_SURFACE_QP
-                            | ENCA_SURFACE_REMOVE)
-} EncaSurface;
-
-typedef enum {
-  ENCA_NAME_STYLE_ENCA,
-  ENCA_NAME_STYLE_RFC1345,
-  ENCA_NAME_STYLE_CSTOCS,
-  ENCA_NAME_STYLE_ICONV,
-  ENCA_NAME_STYLE_HUMAN,
-  ENCA_NAME_STYLE_MIME
-} EncaNameStyle;
-
-typedef enum { /*< flags >*/
-  ENCA_CHARSET_7BIT      = 1 << 0,
-  ENCA_CHARSET_8BIT      = 1 << 1,
-  ENCA_CHARSET_16BIT     = 1 << 2,
-  ENCA_CHARSET_32BIT     = 1 << 3,
-  ENCA_CHARSET_FIXED     = 1 << 4,
-  ENCA_CHARSET_VARIABLE  = 1 << 5,
-  ENCA_CHARSET_BINARY    = 1 << 6,
-  ENCA_CHARSET_REGULAR   = 1 << 7,
-  ENCA_CHARSET_MULTIBYTE = 1 << 8
-} EncaCharsetFlags;
-
-typedef enum {
-  ENCA_EOK = 0,
-  ENCA_EINVALUE,
-  ENCA_EEMPTY,
-  ENCA_EFILTERED,
-  ENCA_ENOCS8,
-  ENCA_ESIGNIF,
-  ENCA_EWINNER,
-  ENCA_EGARBAGE
-} EncaErrno;
-
-#define ENCA_CS_UNKNOWN (-1)
-
-#define ENCA_NOT_A_CHAR 0xffff
-
-/* Published (opaque) typedefs  */
-typedef struct _EncaAnalyserState *EncaAnalyser;
-
-/* Public (transparent) typedefs */
-typedef struct _EncaEncoding EncaEncoding;
-
-struct _EncaEncoding { int charset; EncaSurface surface; };
-
-/* Basic interface. */
-EncaAnalyser  enca_analyser_alloc (const char *langname);
-void          enca_analyser_free  (EncaAnalyser analyser);
-EncaEncoding  enca_analyse        (EncaAnalyser analyser,
-                                   unsigned char *buffer,
-                                   size_t size);
-EncaEncoding  enca_analyse_const  (EncaAnalyser analyser,
-                                   const unsigned char *buffer,
-                                   size_t size);
-int           enca_double_utf8_check (EncaAnalyser analyser,
-                                      const unsigned char *buffer,
-                                      size_t size);
-int*          enca_double_utf8_get_candidates (EncaAnalyser analyser);
-int           enca_errno          (EncaAnalyser analyser);
-const char*   enca_strerror       (EncaAnalyser analyser,
-                                   int errnum);
-
-/* Options. */
-void          enca_set_multibyte              (EncaAnalyser analyser,
-                                               int multibyte);
-int           enca_get_multibyte              (EncaAnalyser analyser);
-void          enca_set_interpreted_surfaces   (EncaAnalyser analyser,
-                                               int interpreted_surfaces);
-int           enca_get_interpreted_surfaces   (EncaAnalyser analyser);
-void          enca_set_ambiguity              (EncaAnalyser analyser,
-                                               int ambiguity);
-int           enca_get_ambiguity              (EncaAnalyser analyser);
-void          enca_set_filtering              (EncaAnalyser analyser,
-                                               int filtering);
-int           enca_get_filtering              (EncaAnalyser analyser);
-void          enca_set_garbage_test           (EncaAnalyser analyser,
-                                               int garabage_test);
-int           enca_get_garbage_test           (EncaAnalyser analyser);
-void          enca_set_termination_strictness (EncaAnalyser analyser,
-                                               int termination_strictness);
-int           enca_get_termination_strictness (EncaAnalyser analyser);
-int           enca_set_significant            (EncaAnalyser analyser,
-                                               size_t significant);
-size_t        enca_get_significant            (EncaAnalyser analyser);
-int           enca_set_threshold              (EncaAnalyser analyser,
-                                               double threshold);
-double        enca_get_threshold              (EncaAnalyser analyser);
-
-/* Names and properties. */
-const char*       enca_charset_name            (int charset,
-                                                EncaNameStyle whatname);
-const char**      enca_get_charset_aliases     (int charset,
-                                                size_t *n);
-char*             enca_get_surface_name        (EncaSurface surface,
-                                                EncaNameStyle whatname);
-EncaEncoding      enca_parse_encoding_name     (const char *name);
-EncaSurface       enca_charset_natural_surface (int charset);
-EncaCharsetFlags  enca_charset_properties      (int charset);
-
-#define enca_charset_is_known(cs) \
-  ((cs) != ENCA_CS_UNKNOWN)
-#define enca_charset_is_7bit(cs) \
-  (enca_charset_properties(cs) & ENCA_CHARSET_7BIT)
-#define enca_charset_is_8bit(cs) \
-  (enca_charset_properties(cs) & ENCA_CHARSET_8BIT)
-#define enca_charset_is_16bit(cs) \
-  (enca_charset_properties(cs) & ENCA_CHARSET_16BIT)
-#define enca_charset_is_32bit(cs) \
-  (enca_charset_properties(cs) & ENCA_CHARSET_32BIT)
-#define enca_charset_is_fixed(cs) \
-  (enca_charset_properties(cs) & ENCA_CHARSET_FIXED)
-#define enca_charset_is_variable(cs) \
-  (enca_charset_properties(cs) & ENCA_CHARSET_VARIABLE)
-#define enca_charset_is_binary(cs) \
-  (enca_charset_properties(cs) & ENCA_CHARSET_BINARY)
-#define enca_charset_is_regular(cs) \
-  (enca_charset_properties(cs) & ENCA_CHARSET_REGULAR)
-#define enca_charset_is_multibyte(cs) \
-  (enca_charset_properties(cs) & ENCA_CHARSET_MULTIBYTE)
-
-/* Auxiliary functions. */
-int           enca_charset_has_ucs2_map  (int charset);
-int           enca_charset_ucs2_map      (int charset,
-                                          unsigned int *buffer);
-size_t        enca_number_of_charsets    (void);
-const char*   enca_analyser_language     (EncaAnalyser analyser);
-const char*   enca_language_english_name (const char *lang);
-const char**  enca_get_languages         (size_t *n);
-int*          enca_get_language_charsets (const char *langname,
-                                          size_t *n);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif
diff --git a/aegisub/libass/msvc/inttypes.h b/aegisub/libass/msvc/inttypes.h
deleted file mode 100644
index 4b3828a21..000000000
--- a/aegisub/libass/msvc/inttypes.h
+++ /dev/null
@@ -1,305 +0,0 @@
-// ISO C9x  compliant inttypes.h for Microsoft Visual Studio
-// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
-// 
-//  Copyright (c) 2006 Alexander Chemeris
-// 
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-// 
-//   1. Redistributions of source code must retain the above copyright notice,
-//      this list of conditions and the following disclaimer.
-// 
-//   2. 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.
-// 
-//   3. The name of the author may 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.
-// 
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef _MSC_VER // [
-#error "Use this header only with Microsoft Visual C++ compilers!"
-#endif // _MSC_VER ]
-
-#ifndef _MSC_INTTYPES_H_ // [
-#define _MSC_INTTYPES_H_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif
-
-#include "stdint.h"
-
-// 7.8 Format conversion of integer types
-
-typedef struct {
-   intmax_t quot;
-   intmax_t rem;
-} imaxdiv_t;
-
-// 7.8.1 Macros for format specifiers
-
-#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [   See footnote 185 at page 198
-
-// The fprintf macros for signed integers are:
-#define PRId8       "d"
-#define PRIi8       "i"
-#define PRIdLEAST8  "d"
-#define PRIiLEAST8  "i"
-#define PRIdFAST8   "d"
-#define PRIiFAST8   "i"
-
-#define PRId16       "hd"
-#define PRIi16       "hi"
-#define PRIdLEAST16  "hd"
-#define PRIiLEAST16  "hi"
-#define PRIdFAST16   "hd"
-#define PRIiFAST16   "hi"
-
-#define PRId32       "I32d"
-#define PRIi32       "I32i"
-#define PRIdLEAST32  "I32d"
-#define PRIiLEAST32  "I32i"
-#define PRIdFAST32   "I32d"
-#define PRIiFAST32   "I32i"
-
-#define PRId64       "I64d"
-#define PRIi64       "I64i"
-#define PRIdLEAST64  "I64d"
-#define PRIiLEAST64  "I64i"
-#define PRIdFAST64   "I64d"
-#define PRIiFAST64   "I64i"
-
-#define PRIdMAX     "I64d"
-#define PRIiMAX     "I64i"
-
-#define PRIdPTR     "Id"
-#define PRIiPTR     "Ii"
-
-// The fprintf macros for unsigned integers are:
-#define PRIo8       "o"
-#define PRIu8       "u"
-#define PRIx8       "x"
-#define PRIX8       "X"
-#define PRIoLEAST8  "o"
-#define PRIuLEAST8  "u"
-#define PRIxLEAST8  "x"
-#define PRIXLEAST8  "X"
-#define PRIoFAST8   "o"
-#define PRIuFAST8   "u"
-#define PRIxFAST8   "x"
-#define PRIXFAST8   "X"
-
-#define PRIo16       "ho"
-#define PRIu16       "hu"
-#define PRIx16       "hx"
-#define PRIX16       "hX"
-#define PRIoLEAST16  "ho"
-#define PRIuLEAST16  "hu"
-#define PRIxLEAST16  "hx"
-#define PRIXLEAST16  "hX"
-#define PRIoFAST16   "ho"
-#define PRIuFAST16   "hu"
-#define PRIxFAST16   "hx"
-#define PRIXFAST16   "hX"
-
-#define PRIo32       "I32o"
-#define PRIu32       "I32u"
-#define PRIx32       "I32x"
-#define PRIX32       "I32X"
-#define PRIoLEAST32  "I32o"
-#define PRIuLEAST32  "I32u"
-#define PRIxLEAST32  "I32x"
-#define PRIXLEAST32  "I32X"
-#define PRIoFAST32   "I32o"
-#define PRIuFAST32   "I32u"
-#define PRIxFAST32   "I32x"
-#define PRIXFAST32   "I32X"
-
-#define PRIo64       "I64o"
-#define PRIu64       "I64u"
-#define PRIx64       "I64x"
-#define PRIX64       "I64X"
-#define PRIoLEAST64  "I64o"
-#define PRIuLEAST64  "I64u"
-#define PRIxLEAST64  "I64x"
-#define PRIXLEAST64  "I64X"
-#define PRIoFAST64   "I64o"
-#define PRIuFAST64   "I64u"
-#define PRIxFAST64   "I64x"
-#define PRIXFAST64   "I64X"
-
-#define PRIoMAX     "I64o"
-#define PRIuMAX     "I64u"
-#define PRIxMAX     "I64x"
-#define PRIXMAX     "I64X"
-
-#define PRIoPTR     "Io"
-#define PRIuPTR     "Iu"
-#define PRIxPTR     "Ix"
-#define PRIXPTR     "IX"
-
-// The fscanf macros for signed integers are:
-#define SCNd8       "d"
-#define SCNi8       "i"
-#define SCNdLEAST8  "d"
-#define SCNiLEAST8  "i"
-#define SCNdFAST8   "d"
-#define SCNiFAST8   "i"
-
-#define SCNd16       "hd"
-#define SCNi16       "hi"
-#define SCNdLEAST16  "hd"
-#define SCNiLEAST16  "hi"
-#define SCNdFAST16   "hd"
-#define SCNiFAST16   "hi"
-
-#define SCNd32       "ld"
-#define SCNi32       "li"
-#define SCNdLEAST32  "ld"
-#define SCNiLEAST32  "li"
-#define SCNdFAST32   "ld"
-#define SCNiFAST32   "li"
-
-#define SCNd64       "I64d"
-#define SCNi64       "I64i"
-#define SCNdLEAST64  "I64d"
-#define SCNiLEAST64  "I64i"
-#define SCNdFAST64   "I64d"
-#define SCNiFAST64   "I64i"
-
-#define SCNdMAX     "I64d"
-#define SCNiMAX     "I64i"
-
-#ifdef _WIN64 // [
-#  define SCNdPTR     "I64d"
-#  define SCNiPTR     "I64i"
-#else  // _WIN64 ][
-#  define SCNdPTR     "ld"
-#  define SCNiPTR     "li"
-#endif  // _WIN64 ]
-
-// The fscanf macros for unsigned integers are:
-#define SCNo8       "o"
-#define SCNu8       "u"
-#define SCNx8       "x"
-#define SCNX8       "X"
-#define SCNoLEAST8  "o"
-#define SCNuLEAST8  "u"
-#define SCNxLEAST8  "x"
-#define SCNXLEAST8  "X"
-#define SCNoFAST8   "o"
-#define SCNuFAST8   "u"
-#define SCNxFAST8   "x"
-#define SCNXFAST8   "X"
-
-#define SCNo16       "ho"
-#define SCNu16       "hu"
-#define SCNx16       "hx"
-#define SCNX16       "hX"
-#define SCNoLEAST16  "ho"
-#define SCNuLEAST16  "hu"
-#define SCNxLEAST16  "hx"
-#define SCNXLEAST16  "hX"
-#define SCNoFAST16   "ho"
-#define SCNuFAST16   "hu"
-#define SCNxFAST16   "hx"
-#define SCNXFAST16   "hX"
-
-#define SCNo32       "lo"
-#define SCNu32       "lu"
-#define SCNx32       "lx"
-#define SCNX32       "lX"
-#define SCNoLEAST32  "lo"
-#define SCNuLEAST32  "lu"
-#define SCNxLEAST32  "lx"
-#define SCNXLEAST32  "lX"
-#define SCNoFAST32   "lo"
-#define SCNuFAST32   "lu"
-#define SCNxFAST32   "lx"
-#define SCNXFAST32   "lX"
-
-#define SCNo64       "I64o"
-#define SCNu64       "I64u"
-#define SCNx64       "I64x"
-#define SCNX64       "I64X"
-#define SCNoLEAST64  "I64o"
-#define SCNuLEAST64  "I64u"
-#define SCNxLEAST64  "I64x"
-#define SCNXLEAST64  "I64X"
-#define SCNoFAST64   "I64o"
-#define SCNuFAST64   "I64u"
-#define SCNxFAST64   "I64x"
-#define SCNXFAST64   "I64X"
-
-#define SCNoMAX     "I64o"
-#define SCNuMAX     "I64u"
-#define SCNxMAX     "I64x"
-#define SCNXMAX     "I64X"
-
-#ifdef _WIN64 // [
-#  define SCNoPTR     "I64o"
-#  define SCNuPTR     "I64u"
-#  define SCNxPTR     "I64x"
-#  define SCNXPTR     "I64X"
-#else  // _WIN64 ][
-#  define SCNoPTR     "lo"
-#  define SCNuPTR     "lu"
-#  define SCNxPTR     "lx"
-#  define SCNXPTR     "lX"
-#endif  // _WIN64 ]
-
-#endif // __STDC_FORMAT_MACROS ]
-
-// 7.8.2 Functions for greatest-width integer types
-
-// 7.8.2.1 The imaxabs function
-#define imaxabs _abs64
-
-// 7.8.2.2 The imaxdiv function
-
-// This is modified version of div() function from Microsoft's div.c found
-// in %MSVC.NET%\crt\src\div.c
-#ifdef STATIC_IMAXDIV // [
-static
-#else // STATIC_IMAXDIV ][
-_inline
-#endif // STATIC_IMAXDIV ]
-imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
-{
-   imaxdiv_t result;
-
-   result.quot = numer / denom;
-   result.rem = numer % denom;
-
-   if (numer < 0 && result.rem > 0) {
-      // did division wrong; must fix up
-      ++result.quot;
-      result.rem -= denom;
-   }
-
-   return result;
-}
-
-// 7.8.2.3 The strtoimax and strtoumax functions
-#define strtoimax _strtoi64
-#define strtoumax _strtoui64
-
-// 7.8.2.4 The wcstoimax and wcstoumax functions
-#define wcstoimax _wcstoi64
-#define wcstoumax _wcstoui64
-
-
-#endif // _MSC_INTTYPES_H_ ]
diff --git a/aegisub/libass/msvc/stdint.h b/aegisub/libass/msvc/stdint.h
deleted file mode 100644
index d02608a59..000000000
--- a/aegisub/libass/msvc/stdint.h
+++ /dev/null
@@ -1,247 +0,0 @@
-// ISO C9x  compliant stdint.h for Microsoft Visual Studio
-// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
-// 
-//  Copyright (c) 2006-2008 Alexander Chemeris
-// 
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-// 
-//   1. Redistributions of source code must retain the above copyright notice,
-//      this list of conditions and the following disclaimer.
-// 
-//   2. 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.
-// 
-//   3. The name of the author may 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.
-// 
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef _MSC_VER // [
-#error "Use this header only with Microsoft Visual C++ compilers!"
-#endif // _MSC_VER ]
-
-#ifndef _MSC_STDINT_H_ // [
-#define _MSC_STDINT_H_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif
-
-#include <limits.h>
-
-// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
-// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
-// or compiler give many errors like this:
-//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed
-#ifdef __cplusplus
-extern "C" {
-#endif
-#  include <wchar.h>
-#ifdef __cplusplus
-}
-#endif
-
-// Define _W64 macros to mark types changing their size, like intptr_t.
-#ifndef _W64
-#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
-#     define _W64 __w64
-#  else
-#     define _W64
-#  endif
-#endif
-
-
-// 7.18.1 Integer types
-
-// 7.18.1.1 Exact-width integer types
-
-// Visual Studio 6 and Embedded Visual C++ 4 doesn't
-// realize that, e.g. char has the same size as __int8
-// so we give up on __intX for them.
-#if (_MSC_VER < 1300)
-   typedef signed char       int8_t;
-   typedef signed short      int16_t;
-   typedef signed int        int32_t;
-   typedef unsigned char     uint8_t;
-   typedef unsigned short    uint16_t;
-   typedef unsigned int      uint32_t;
-#else
-   typedef signed __int8     int8_t;
-   typedef signed __int16    int16_t;
-   typedef signed __int32    int32_t;
-   typedef unsigned __int8   uint8_t;
-   typedef unsigned __int16  uint16_t;
-   typedef unsigned __int32  uint32_t;
-#endif
-typedef signed __int64       int64_t;
-typedef unsigned __int64     uint64_t;
-
-
-// 7.18.1.2 Minimum-width integer types
-typedef int8_t    int_least8_t;
-typedef int16_t   int_least16_t;
-typedef int32_t   int_least32_t;
-typedef int64_t   int_least64_t;
-typedef uint8_t   uint_least8_t;
-typedef uint16_t  uint_least16_t;
-typedef uint32_t  uint_least32_t;
-typedef uint64_t  uint_least64_t;
-
-// 7.18.1.3 Fastest minimum-width integer types
-typedef int8_t    int_fast8_t;
-typedef int16_t   int_fast16_t;
-typedef int32_t   int_fast32_t;
-typedef int64_t   int_fast64_t;
-typedef uint8_t   uint_fast8_t;
-typedef uint16_t  uint_fast16_t;
-typedef uint32_t  uint_fast32_t;
-typedef uint64_t  uint_fast64_t;
-
-// 7.18.1.4 Integer types capable of holding object pointers
-#ifdef _WIN64 // [
-   typedef signed __int64    intptr_t;
-   typedef unsigned __int64  uintptr_t;
-#else // _WIN64 ][
-   typedef _W64 signed int   intptr_t;
-   typedef _W64 unsigned int uintptr_t;
-#endif // _WIN64 ]
-
-// 7.18.1.5 Greatest-width integer types
-typedef int64_t   intmax_t;
-typedef uint64_t  uintmax_t;
-
-
-// 7.18.2 Limits of specified-width integer types
-
-#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259
-
-// 7.18.2.1 Limits of exact-width integer types
-#define INT8_MIN     ((int8_t)_I8_MIN)
-#define INT8_MAX     _I8_MAX
-#define INT16_MIN    ((int16_t)_I16_MIN)
-#define INT16_MAX    _I16_MAX
-#define INT32_MIN    ((int32_t)_I32_MIN)
-#define INT32_MAX    _I32_MAX
-#define INT64_MIN    ((int64_t)_I64_MIN)
-#define INT64_MAX    _I64_MAX
-#define UINT8_MAX    _UI8_MAX
-#define UINT16_MAX   _UI16_MAX
-#define UINT32_MAX   _UI32_MAX
-#define UINT64_MAX   _UI64_MAX
-
-// 7.18.2.2 Limits of minimum-width integer types
-#define INT_LEAST8_MIN    INT8_MIN
-#define INT_LEAST8_MAX    INT8_MAX
-#define INT_LEAST16_MIN   INT16_MIN
-#define INT_LEAST16_MAX   INT16_MAX
-#define INT_LEAST32_MIN   INT32_MIN
-#define INT_LEAST32_MAX   INT32_MAX
-#define INT_LEAST64_MIN   INT64_MIN
-#define INT_LEAST64_MAX   INT64_MAX
-#define UINT_LEAST8_MAX   UINT8_MAX
-#define UINT_LEAST16_MAX  UINT16_MAX
-#define UINT_LEAST32_MAX  UINT32_MAX
-#define UINT_LEAST64_MAX  UINT64_MAX
-
-// 7.18.2.3 Limits of fastest minimum-width integer types
-#define INT_FAST8_MIN    INT8_MIN
-#define INT_FAST8_MAX    INT8_MAX
-#define INT_FAST16_MIN   INT16_MIN
-#define INT_FAST16_MAX   INT16_MAX
-#define INT_FAST32_MIN   INT32_MIN
-#define INT_FAST32_MAX   INT32_MAX
-#define INT_FAST64_MIN   INT64_MIN
-#define INT_FAST64_MAX   INT64_MAX
-#define UINT_FAST8_MAX   UINT8_MAX
-#define UINT_FAST16_MAX  UINT16_MAX
-#define UINT_FAST32_MAX  UINT32_MAX
-#define UINT_FAST64_MAX  UINT64_MAX
-
-// 7.18.2.4 Limits of integer types capable of holding object pointers
-#ifdef _WIN64 // [
-#  define INTPTR_MIN   INT64_MIN
-#  define INTPTR_MAX   INT64_MAX
-#  define UINTPTR_MAX  UINT64_MAX
-#else // _WIN64 ][
-#  define INTPTR_MIN   INT32_MIN
-#  define INTPTR_MAX   INT32_MAX
-#  define UINTPTR_MAX  UINT32_MAX
-#endif // _WIN64 ]
-
-// 7.18.2.5 Limits of greatest-width integer types
-#define INTMAX_MIN   INT64_MIN
-#define INTMAX_MAX   INT64_MAX
-#define UINTMAX_MAX  UINT64_MAX
-
-// 7.18.3 Limits of other integer types
-
-#ifdef _WIN64 // [
-#  define PTRDIFF_MIN  _I64_MIN
-#  define PTRDIFF_MAX  _I64_MAX
-#else  // _WIN64 ][
-#  define PTRDIFF_MIN  _I32_MIN
-#  define PTRDIFF_MAX  _I32_MAX
-#endif  // _WIN64 ]
-
-#define SIG_ATOMIC_MIN  INT_MIN
-#define SIG_ATOMIC_MAX  INT_MAX
-
-#ifndef SIZE_MAX // [
-#  ifdef _WIN64 // [
-#     define SIZE_MAX  _UI64_MAX
-#  else // _WIN64 ][
-#     define SIZE_MAX  _UI32_MAX
-#  endif // _WIN64 ]
-#endif // SIZE_MAX ]
-
-// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
-#ifndef WCHAR_MIN // [
-#  define WCHAR_MIN  0
-#endif  // WCHAR_MIN ]
-#ifndef WCHAR_MAX // [
-#  define WCHAR_MAX  _UI16_MAX
-#endif  // WCHAR_MAX ]
-
-#define WINT_MIN  0
-#define WINT_MAX  _UI16_MAX
-
-#endif // __STDC_LIMIT_MACROS ]
-
-
-// 7.18.4 Limits of other integer types
-
-#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260
-
-// 7.18.4.1 Macros for minimum-width integer constants
-
-#define INT8_C(val)  val##i8
-#define INT16_C(val) val##i16
-#define INT32_C(val) val##i32
-#define INT64_C(val) val##i64
-
-#define UINT8_C(val)  val##ui8
-#define UINT16_C(val) val##ui16
-#define UINT32_C(val) val##ui32
-#define UINT64_C(val) val##ui64
-
-// 7.18.4.2 Macros for greatest-width integer constants
-#define INTMAX_C   INT64_C
-#define UINTMAX_C  UINT64_C
-
-#endif // __STDC_CONSTANT_MACROS ]
-
-
-#endif // _MSC_STDINT_H_ ]
diff --git a/aegisub/libass/msvc/strings.h b/aegisub/libass/msvc/strings.h
deleted file mode 100644
index 8279fd78d..000000000
--- a/aegisub/libass/msvc/strings.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#define strncasecmp _strnicmp
-#define strcasecmp _stricmp
-
diff --git a/aegisub/libass/msvc/unistd.h b/aegisub/libass/msvc/unistd.h
deleted file mode 100644
index e69de29bb..000000000
diff --git a/aegisub/libass/wscript b/aegisub/libass/wscript
deleted file mode 100644
index fb470d90a..000000000
--- a/aegisub/libass/wscript
+++ /dev/null
@@ -1,26 +0,0 @@
-#! /usr/bin/env python
-# encoding: utf-8
-#
-# Copyright (c) 2009, Kevin Ollivier <kollivier@aegisub.org>
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-def build(bld):
-    obj = bld.new_task_gen(
-        features = 'cc cstaticlib',
-        target = 'ass_aegisub',
-        defines = 'CONFIG_ICONV CONFIG_FONTCONFIG',
-        includes = '.',
-        uselib = 'FREETYPE2')
-
-    obj.find_sources_in_dirs('.')
diff --git a/aegisub/libffms/Makefile b/aegisub/libffms/Makefile
deleted file mode 100644
index 72362a441..000000000
--- a/aegisub/libffms/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-include ../Makefile.inc
-
-CXXFLAGS = -Icore -Iinclude -D__UNIX__ -DFFMS_EXPORTS -DHAVE_STRLCPY -D__STDC_CONSTANT_MACROS -fPIC
-CXXFLAGS += $(CFLAGS_LIBAVFORMAT) $(CFLAGS_LIBAVCODEC) $(CFLAGS_LIBAVUTIL) $(CFLAGS_LIBPOSTPROC)
-
-LIB = libffmpegsource_aegisub.a
-
-SRC = \
-	src/core/audiosource.cpp \
-	src/core/ffms.cpp \
-	src/core/indexing.cpp \
-	src/core/lavfaudio.cpp \
-	src/core/lavfindexer.cpp \
-	src/core/lavfvideo.cpp \
-	src/core/matroskaaudio.cpp \
-	src/core/matroskaindexer.cpp \
-	src/core/matroskaparser.c \
-	src/core/matroskavideo.cpp \
-	src/core/stdiostream.c \
-	src/core/utils.cpp \
-	src/core/videosource.cpp \
-	src/core/wave64writer.cpp
-
-HEADER = \
-	src/core/*.h \
-	include/*.h
-
-include ../Makefile.target
--include src/core/*.d
-
diff --git a/aegisub/libffms/include/ffms.h b/aegisub/libffms/include/ffms.h
deleted file mode 100644
index 54df8ccb5..000000000
--- a/aegisub/libffms/include/ffms.h
+++ /dev/null
@@ -1,294 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#ifndef FFMS_H
-#define FFMS_H
-
-// Version format: major - minor - micro - bump
-#define FFMS_VERSION ((2 << 24) | (14 << 16) | (1 << 8) | 1)
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-#	define FFMS_EXTERN_C extern "C"
-#	define FFMS_CLASS_TYPE class
-#else
-#	define FFMS_EXTERN_C
-#	define FFMS_CLASS_TYPE struct
-#endif
-
-#ifdef _WIN32
-#	define FFMS_CC __stdcall
-#	ifdef _MSC_VER
-#		ifdef FFMS_EXPORTS
-#			define FFMS_API(ret) FFMS_EXTERN_C __declspec(dllexport) ret FFMS_CC
-#		else
-#			define FFMS_API(ret) FFMS_EXTERN_C __declspec(dllimport) ret FFMS_CC
-#		endif
-#	else
-#		define FFMS_API(ret) FFMS_EXTERN_C ret FFMS_CC
-#	endif
-#else
-#	define FFMS_CC
-#	define FFMS_API(ret) FFMS_EXTERN_C ret FFMS_CC
-#endif
-
-typedef struct {
-	int ErrorType;
-	int SubType;
-	int BufferSize;
-	char *Buffer;
-} FFMS_ErrorInfo;
-
-typedef FFMS_CLASS_TYPE FFMS_VideoSource FFMS_VideoSource;
-typedef FFMS_CLASS_TYPE FFMS_AudioSource FFMS_AudioSource;
-typedef FFMS_CLASS_TYPE FFMS_Indexer FFMS_Indexer;
-typedef FFMS_CLASS_TYPE FFMS_Index FFMS_Index;
-typedef FFMS_CLASS_TYPE FFMS_Track FFMS_Track;
-
-enum FFMS_Errors {
-	// No error
-	FFMS_ERROR_SUCCESS = 0,
-
-	// Main types - where the error occurred
-	FFMS_ERROR_INDEX = 1,
-	FFMS_ERROR_INDEXING,
-	FFMS_ERROR_POSTPROCESSING,
-	FFMS_ERROR_SCALING,
-	FFMS_ERROR_DECODING,
-	FFMS_ERROR_SEEKING,
-	FFMS_ERROR_PARSER,
-	FFMS_ERROR_TRACK,
-	FFMS_ERROR_WAVE_WRITER,
-	FFMS_ERROR_CANCELLED,
-
-	// Subtypes - what caused the error
-	FFMS_ERROR_UNKNOWN = 20,
-	FFMS_ERROR_UNSUPPORTED,
-	FFMS_ERROR_FILE_READ,
-	FFMS_ERROR_FILE_WRITE,
-	FFMS_ERROR_NO_FILE,
-	FFMS_ERROR_VERSION,
-	FFMS_ERROR_ALLOCATION_FAILED,
-	FFMS_ERROR_INVALID_ARGUMENT,
-	FFMS_ERROR_CODEC,
-	FFMS_ERROR_NOT_AVAILABLE,
-	FFMS_ERROR_FILE_MISMATCH,
-	FFMS_ERROR_USER
-};
-
-enum FFMS_Sources {
-	FFMS_SOURCE_LAVF		= 0x01,
-	FFMS_SOURCE_MATROSKA	= 0x02,
-	FFMS_SOURCE_HAALIMPEG	= 0x04,
-	FFMS_SOURCE_HAALIOGG	= 0x08
-};
-
-enum FFMS_CPUFeatures {
-	FFMS_CPU_CAPS_MMX		= 0x01,
-	FFMS_CPU_CAPS_MMX2		= 0x02,
-	FFMS_CPU_CAPS_3DNOW		= 0x04,
-	FFMS_CPU_CAPS_ALTIVEC	= 0x08,
-	FFMS_CPU_CAPS_BFIN		= 0x10,
-	FFMS_CPU_CAPS_SSE2      = 0x20
-};
-
-enum FFMS_SeekMode {
-	FFMS_SEEK_LINEAR_NO_RW	= -1,
-	FFMS_SEEK_LINEAR		= 0,
-	FFMS_SEEK_NORMAL		= 1,
-	FFMS_SEEK_UNSAFE		= 2,
-	FFMS_SEEK_AGGRESSIVE	= 3
-};
-
-enum FFMS_IndexErrorHandling {
-	FFMS_IEH_ABORT = 0,
-	FFMS_IEH_CLEAR_TRACK = 1,
-	FFMS_IEH_STOP_TRACK = 2,
-	FFMS_IEH_IGNORE = 3
-};
-
-enum FFMS_TrackType {
-	FFMS_TYPE_UNKNOWN = -1,
-	FFMS_TYPE_VIDEO,
-    FFMS_TYPE_AUDIO,
-    FFMS_TYPE_DATA,
-    FFMS_TYPE_SUBTITLE,
-    FFMS_TYPE_ATTACHMENT
-};
-
-enum FFMS_SampleFormat {
-    FFMS_FMT_U8 = 0,
-    FFMS_FMT_S16,
-    FFMS_FMT_S32,
-    FFMS_FMT_FLT,
-    FFMS_FMT_DBL
-};
-
-enum FFMS_AudioChannel {
-	FFMS_CH_FRONT_LEFT				= 0x00000001,
-	FFMS_CH_FRONT_RIGHT				= 0x00000002,
-	FFMS_CH_FRONT_CENTER			= 0x00000004,
-	FFMS_CH_LOW_FREQUENCY			= 0x00000008,
-	FFMS_CH_BACK_LEFT				= 0x00000010,
-	FFMS_CH_BACK_RIGHT				= 0x00000020,
-	FFMS_CH_FRONT_LEFT_OF_CENTER	= 0x00000040,
-	FFMS_CH_FRONT_RIGHT_OF_CENTER	= 0x00000080,
-	FFMS_CH_BACK_CENTER				= 0x00000100,
-	FFMS_CH_SIDE_LEFT				= 0x00000200,
-	FFMS_CH_SIDE_RIGHT				= 0x00000400,
-	FFMS_CH_TOP_CENTER				= 0x00000800,
-	FFMS_CH_TOP_FRONT_LEFT			= 0x00001000,
-	FFMS_CH_TOP_FRONT_CENTER		= 0x00002000,
-	FFMS_CH_TOP_FRONT_RIGHT			= 0x00004000,
-	FFMS_CH_TOP_BACK_LEFT			= 0x00008000,
-	FFMS_CH_TOP_BACK_CENTER			= 0x00010000,
-	FFMS_CH_TOP_BACK_RIGHT			= 0x00020000,
-	FFMS_CH_STEREO_LEFT				= 0x20000000,
-	FFMS_CH_STEREO_RIGHT			= 0x40000000
-};
-
-enum FFMS_Resizers {
-	FFMS_RESIZER_FAST_BILINEAR	= 0x0001,
-	FFMS_RESIZER_BILINEAR		= 0x0002,
-	FFMS_RESIZER_BICUBIC		= 0x0004,
-	FFMS_RESIZER_X				= 0x0008,
-	FFMS_RESIZER_POINT			= 0x0010,
-	FFMS_RESIZER_AREA			= 0x0020,
-	FFMS_RESIZER_BICUBLIN		= 0x0040,
-	FFMS_RESIZER_GAUSS			= 0x0080,
-	FFMS_RESIZER_SINC			= 0x0100,
-	FFMS_RESIZER_LANCZOS		= 0x0200,
-	FFMS_RESIZER_SPLINE			= 0x0400
-};
-
-enum FFMS_AudioDelayModes {
-	FFMS_DELAY_NO_SHIFT				= -3,
-	FFMS_DELAY_TIME_ZERO			= -2,
-	FFMS_DELAY_FIRST_VIDEO_TRACK	= -1
-};
-
-typedef struct {
-	uint8_t *Data[4];
-	int Linesize[4];
-	int EncodedWidth;
-	int EncodedHeight;
-	int EncodedPixelFormat;
-	int ScaledWidth;
-	int ScaledHeight;
-	int ConvertedPixelFormat;
-	int KeyFrame;
-	int RepeatPict;
-	int InterlacedFrame;
-	int TopFieldFirst;
-	char PictType;
-} FFMS_Frame;
-
-typedef struct {
-	int64_t Num;
-	int64_t Den;
-} FFMS_TrackTimeBase;
-
-#define FFMS_FRAMEINFO_COMMON int64_t PTS; int RepeatPict; int KeyFrame;
-
-typedef struct {
-	FFMS_FRAMEINFO_COMMON
-} FFMS_FrameInfo;
-
-typedef struct {
-	int FPSDenominator;
-	int FPSNumerator;
-	int RFFDenominator;
-	int RFFNumerator;
-	int NumFrames;
-	int SARNum;
-	int SARDen;
-	int CropTop;
-	int CropBottom;
-	int CropLeft;
-	int CropRight;
-	int TopFieldFirst;
-	int ColorSpace; // same as in the MPEG-2 specs, see AVColorSpace in avcodec.h
-	int ColorRange; // 0=unspecified, 1=16-235, 2=0-255
-	double FirstTime;
-	double LastTime;
-} FFMS_VideoProperties;
-
-typedef struct {
-	int SampleFormat;
-	int SampleRate;
-	int BitsPerSample;
-	int Channels;
-	int64_t ChannelLayout;
-	int64_t NumSamples;
-	double FirstTime;
-	double LastTime;
-} FFMS_AudioProperties;
-
-typedef int (FFMS_CC *TIndexCallback)(int64_t Current, int64_t Total, void *ICPrivate);
-typedef int (FFMS_CC *TAudioNameCallback)(const char *SourceFile, int Track, const FFMS_AudioProperties *AP, char *FileName, int FNSize, void *Private);
-
-// Most functions return 0 on success
-// Functions without error message output can be assumed to never fail in a graceful way
-FFMS_API(void) FFMS_Init(int CPUFeatures, int UseUTF8Paths);
-FFMS_API(int) FFMS_GetLogLevel();
-FFMS_API(void) FFMS_SetLogLevel(int Level);
-FFMS_API(FFMS_VideoSource *) FFMS_CreateVideoSource(const char *SourceFile, int Track, FFMS_Index *Index, int Threads, int SeekMode, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(FFMS_AudioSource *) FFMS_CreateAudioSource(const char *SourceFile, int Track, FFMS_Index *Index, int DelayMode, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(void) FFMS_DestroyVideoSource(FFMS_VideoSource *V);
-FFMS_API(void) FFMS_DestroyAudioSource(FFMS_AudioSource *A);
-FFMS_API(const FFMS_VideoProperties *) FFMS_GetVideoProperties(FFMS_VideoSource *V);
-FFMS_API(const FFMS_AudioProperties *) FFMS_GetAudioProperties(FFMS_AudioSource *A);
-FFMS_API(const FFMS_Frame *) FFMS_GetFrame(FFMS_VideoSource *V, int n, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(const FFMS_Frame *) FFMS_GetFrameByTime(FFMS_VideoSource *V, double Time, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(int) FFMS_GetAudio(FFMS_AudioSource *A, void *Buf, int64_t Start, int64_t Count, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(int) FFMS_SetOutputFormatV(FFMS_VideoSource *V, int64_t TargetFormats, int Width, int Height, int Resizer, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(void) FFMS_ResetOutputFormatV(FFMS_VideoSource *V);
-FFMS_API(int) FFMS_SetPP(FFMS_VideoSource *V, const char *PP, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(void) FFMS_ResetPP(FFMS_VideoSource *V);
-FFMS_API(void) FFMS_DestroyIndex(FFMS_Index *Index);
-FFMS_API(int) FFMS_GetSourceType(FFMS_Index *Index);
-FFMS_API(int) FFMS_GetFirstTrackOfType(FFMS_Index *Index, int TrackType, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(int) FFMS_GetFirstIndexedTrackOfType(FFMS_Index *Index, int TrackType, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(int) FFMS_GetNumTracks(FFMS_Index *Index);
-FFMS_API(int) FFMS_GetNumTracksI(FFMS_Indexer *Indexer);
-FFMS_API(int) FFMS_GetTrackType(FFMS_Track *T);
-FFMS_API(int) FFMS_GetTrackTypeI(FFMS_Indexer *Indexer, int Track);
-FFMS_API(const char *) FFMS_GetCodecNameI(FFMS_Indexer *Indexer, int Track);
-FFMS_API(int) FFMS_GetNumFrames(FFMS_Track *T);
-FFMS_API(const FFMS_FrameInfo *) FFMS_GetFrameInfo(FFMS_Track *T, int Frame);
-FFMS_API(FFMS_Track *) FFMS_GetTrackFromIndex(FFMS_Index *Index, int Track);
-FFMS_API(FFMS_Track *) FFMS_GetTrackFromVideo(FFMS_VideoSource *V);
-FFMS_API(FFMS_Track *) FFMS_GetTrackFromAudio(FFMS_AudioSource *A);
-FFMS_API(const FFMS_TrackTimeBase *) FFMS_GetTimeBase(FFMS_Track *T);
-FFMS_API(int) FFMS_WriteTimecodes(FFMS_Track *T, const char *TimecodeFile, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(FFMS_Index *) FFMS_MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, int ErrorHandling, TIndexCallback IC, void *ICPrivate, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(int) FFMS_DefaultAudioFilename(const char *SourceFile, int Track, const FFMS_AudioProperties *AP, char *FileName, int FNSize, void *Private);
-FFMS_API(FFMS_Indexer *) FFMS_CreateIndexer(const char *SourceFile, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(FFMS_Index *) FFMS_DoIndexing(FFMS_Indexer *Indexer, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, int ErrorHandling, TIndexCallback IC, void *ICPrivate, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(void) FFMS_CancelIndexing(FFMS_Indexer *Indexer);
-FFMS_API(FFMS_Index *) FFMS_ReadIndex(const char *IndexFile, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(int) FFMS_IndexBelongsToFile(FFMS_Index *Index, const char *SourceFile, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FFMS_Index *Index, FFMS_ErrorInfo *ErrorInfo);
-FFMS_API(int) FFMS_GetPixFmt(const char *Name);
-FFMS_API(int) FFMS_GetPresentSources();
-FFMS_API(int) FFMS_GetEnabledSources();
-
-#endif
diff --git a/aegisub/libffms/include/ffmscompat.h b/aegisub/libffms/include/ffmscompat.h
deleted file mode 100644
index 3e21fb396..000000000
--- a/aegisub/libffms/include/ffmscompat.h
+++ /dev/null
@@ -1,85 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#ifndef FFMSCOMPAT_H
-#define	FFMSCOMPAT_H
-
-#ifdef _WIN32
-#	define snprintf _snprintf
-#	ifdef __MINGW32__
-#		define fseeko fseeko64
-#		define ftello ftello64
-#	else
-#		define fseeko _fseeki64
-#		define ftello _ftelli64
-#	endif
-#endif
-
-// Compatibility with older/newer ffmpegs
-#ifdef LIBAVFORMAT_VERSION_INT
-#	if (LIBAVFORMAT_VERSION_INT) < (AV_VERSION_INT(52,34,1)) 
-#		define ff_codec_bmp_tags codec_bmp_tags
-#		define ff_codec_movvideo_tags codec_movvideo_tags
-#		define ff_codec_wav_tags codec_wav_tags
-#	endif
-#endif
-
-#ifdef LIBAVCODEC_VERSION_INT
-#	if (LIBAVCODEC_VERSION_INT) >= (AV_VERSION_INT(52,29,0))
-#		define FFMS_HAVE_FFMPEG_COLORSPACE_INFO
-#	else
-#		define AVCOL_RANGE_JPEG 2
-#		ifdef _MSC_VER
-#			pragma message("WARNING: Your FFmpeg is too old to support reporting colorspace and luma range information. The corresponding fields of FFMS_VideoProperties will be set to 0. Please update FFmpeg to get rid of this warning.")
-#		else
-#			warning "Your FFmpeg is too old to support reporting colorspace and luma range information. The corresponding fields of FFMS_VideoProperties will be set to 0. Please update FFmpeg to get rid of this warning."
-#		endif
-#	endif
-#	if (LIBAVCODEC_VERSION_INT) < (AV_VERSION_INT(52,30,2))
-#		define AV_PKT_FLAG_KEY PKT_FLAG_KEY
-#	endif
-#	if (LIBAVCODEC_VERSION_INT) >= (AV_VERSION_INT(52,94,3)) // there are ~3 revisions where this will break but fixing that is :effort:
-#		undef SampleFormat
-#	else
-#		define AVSampleFormat SampleFormat
-#		define av_get_bits_per_sample_fmt av_get_bits_per_sample_format
-#		define AV_SAMPLE_FMT_U8		SAMPLE_FMT_U8
-#		define AV_SAMPLE_FMT_S16	SAMPLE_FMT_S16
-#		define AV_SAMPLE_FMT_S32	SAMPLE_FMT_S32
-#		define AV_SAMPLE_FMT_FLT	SAMPLE_FMT_FLT
-#		define AV_SAMPLE_FMT_DBL	SAMPLE_FMT_DBL
-#	endif
-#endif
-
-#ifdef LIBAVUTIL_VERSION_INT
-#	if (LIBAVUTIL_VERSION_INT) < (AV_VERSION_INT(50, 8, 0))
-#		define av_get_pix_fmt avcodec_get_pix_fmt
-#	endif
-#endif
-
-#ifdef LIBSWSCALE_VERSION_INT
-#	if (LIBSWSCALE_VERSION_INT) < (AV_VERSION_INT(0,8,0))
-#		define FFMS_SWS_CONST_PARAM
-#	else
-#		define FFMS_SWS_CONST_PARAM const
-#	endif
-#endif
-
-#endif // FFMSCOMPAT_H
diff --git a/aegisub/libffms/src/core/audiosource.cpp b/aegisub/libffms/src/core/audiosource.cpp
deleted file mode 100644
index 136d5b93b..000000000
--- a/aegisub/libffms/src/core/audiosource.cpp
+++ /dev/null
@@ -1,304 +0,0 @@
-//  Copyright (c) 2010 Thomas Goyne <tgoyne@gmail.com>
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include "audiosource.h"
-
-#include <algorithm>
-#include <cassert>
-
-FFMS_AudioSource::FFMS_AudioSource(const char *SourceFile, FFMS_Index &Index, int Track)
-: Delay(0)
-, MaxCacheBlocks(50)
-, BytesPerSample(0)
-, Decoded(0)
-, CurrentSample(-1)
-, PacketNumber(0)
-, CurrentFrame(NULL)
-, TrackNumber(Track)
-, SeekOffset(0)
-, DecodingBuffer(AVCODEC_MAX_AUDIO_FRAME_SIZE * 10)
-{
-	if (Track < 0 || Track >= static_cast<int>(Index.size()))
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
-			"Out of bounds track index selected");
-
-	if (Index[Track].TT != FFMS_TYPE_AUDIO)
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
-			"Not an audio track");
-
-	if (Index[Track].empty())
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
-			"Audio track contains no audio frames");
-
-	Frames = Index[Track];
-
-	if (!Index.CompareFileSignature(SourceFile))
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_MISMATCH,
-			"The index does not match the source file");
-}
-void FFMS_AudioSource::Init(FFMS_Index &Index, int DelayMode) {
-	// The first packet after a seek is often decoded incorrectly, which
-	// makes it impossible to ever correctly seek back to the beginning, so
-	// store the first block now
-
-	// In addition, anything with the same PTS as the first packet can't be
-	// distinguished from the first packet and so can't be seeked to, so
-	// store those as well
-
-	// Some of LAVF's splitters don't like to seek to the beginning of the
-	// file (ts and?), so cache a few blocks even if PTSes are unique
-	// Packet 7 is the last packet I've had be unseekable to, so cache up to
-	// 10 for a bit of an extra buffer
-	CacheIterator end = Cache.end();
-	while (PacketNumber < Frames.size() &&
-		((Frames[0].PTS != ffms_av_nopts_value && Frames[PacketNumber].PTS == Frames[0].PTS) ||
-		 Cache.size() < 10)) {
-
-		DecodeNextBlock();
-		if (Decoded)
-			CacheBlock(end, CurrentSample, Decoded, &DecodingBuffer[0]);
-	}
-	// Store the iterator to the last element of the cache which is used for
-	// correctness rather than speed, so that when looking for one to delete
-	// we know how much to skip
-	CacheNoDelete = Cache.end();
-	--CacheNoDelete;
-
-	// Read properties of the audio which may not be available until the first
-	// frame has been decoded
-	FillAP(AP, CodecContext, Frames);
-
-	if (AP.SampleRate <= 0 || AP.BitsPerSample <= 0)
-		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
-			"Codec returned zero size audio");
-
-	if (DelayMode < FFMS_DELAY_NO_SHIFT)
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
-			"Bad audio delay compensation mode");
-
-	if (DelayMode == FFMS_DELAY_NO_SHIFT) return;
-
-	if (DelayMode > (signed)Index.size())
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
-			"Out of bounds track index selected for audio delay compensation");
-
-	if (DelayMode >= 0 && Index[DelayMode].TT != FFMS_TYPE_VIDEO)
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
-			"Audio delay compensation must be relative to a video track");
-
-	double AdjustRelative = 0;
-	if (DelayMode != FFMS_DELAY_TIME_ZERO) {
-		if (DelayMode == FFMS_DELAY_FIRST_VIDEO_TRACK) {
-			for (size_t i = 0; i < Index.size(); ++i) {
-				if (Index[i].TT == FFMS_TYPE_VIDEO) {
-					DelayMode = i;
-					break;
-				}
-			}
-		}
-
-		if (DelayMode >= 0) {
-			const FFMS_Track &VTrack = Index[DelayMode];
-			AdjustRelative = VTrack[0].PTS * VTrack.TB.Num / (double)VTrack.TB.Den / 1000.;
-		}
-	}
-
-	Delay = static_cast<int64_t>((AdjustRelative - Frames[0].PTS) * AP.SampleRate + .5);
-	AP.NumSamples -= Delay;
-}
-
-void FFMS_AudioSource::CacheBlock(CacheIterator &pos, int64_t Start, size_t Samples, uint8_t *SrcData) {
-	Cache.insert(pos, AudioBlock(Start, Samples, SrcData, Samples * BytesPerSample));
-
-	if (Cache.size() >= MaxCacheBlocks) {
-		// Kill the oldest one
-		CacheIterator min = CacheNoDelete;
-		// Never drop the first one as the first packet decoded after a seek
-		// is often decoded incorrectly and we can't seek to before the first one
-		++min;
-		for (CacheIterator it = min; it != Cache.end(); ++it)
-			if (it->Age < min->Age) min = it;
-		if (min == pos) ++pos;
-		Cache.erase(min);
-	}
-}
-
-void FFMS_AudioSource::DecodeNextBlock() {
-	if (BytesPerSample == 0) BytesPerSample = (av_get_bits_per_sample_fmt(CodecContext->sample_fmt) * CodecContext->channels) / 8;
-
-	CurrentFrame = &Frames[PacketNumber];
-
-	AVPacket Packet;
-	if (!ReadPacket(&Packet))
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_UNKNOWN, "ReadPacket unexpectedly failed to read a packet");
-
-	// ReadPacket may have changed the packet number
-	CurrentFrame = &Frames[PacketNumber];
-	CurrentSample = CurrentFrame->SampleStart;
-	++PacketNumber;
-
-	uint8_t *Buf = &DecodingBuffer[0];
-	uint8_t *Data = Packet.data;
-	while (Packet.size > 0) {
-		int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE * 10 - (Buf - &DecodingBuffer[0]);
-		int Ret = avcodec_decode_audio3(CodecContext, (int16_t *)Buf, &TempOutputBufSize, &Packet);
-
-		// Should only ever happen if the user chose to ignore decoding errors
-		// during indexing, so continue to just ignore decoding errors
-		if (Ret < 0) break;
-
-		if (Ret > 0) {
-			Packet.size -= Ret;
-			Packet.data += Ret;
-			Buf += TempOutputBufSize;
-		}
-	}
-	Packet.data = Data;
-	FreePacket(&Packet);
-
-	Decoded = (Buf - &DecodingBuffer[0]) / BytesPerSample;
-	if (Decoded == 0) {
-		// zero sample packets aren't included in the index so we didn't
-		// actually move to the next packet
-		--PacketNumber;
-	}
-}
-
-static bool SampleStartComp(const TFrameInfo &a, const TFrameInfo &b) {
-	return a.SampleStart < b.SampleStart;
-}
-
-void FFMS_AudioSource::GetAudio(void *Buf, int64_t Start, int64_t Count) {
-	if (Start < 0 || Start + Count > AP.NumSamples || Count < 0)
-		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_INVALID_ARGUMENT,
-			"Out of bounds audio samples requested");
-
-	uint8_t *Dst = static_cast<uint8_t*>(Buf);
-
-	// Apply audio delay (if any) and fill any samples before the start time with zero
-	Start -= Delay;
-	if (Start < 0) {
-		size_t Bytes = static_cast<size_t>(BytesPerSample * FFMIN(-Start, Count));
-		memset(Dst, 0, Bytes);
-
-		Count += Start;
-		// Entire request was before the start of the audio
-		if (Count <= 0) return;
-
-		Start = 0;
-		Dst += Bytes;
-	}
-
-	CacheIterator it = Cache.begin();
-
-	while (Count > 0) {
-		// Find first useful cache block
-		while (it != Cache.end() && it->Start + it->Samples <= Start) ++it;
-
-		// Cache has the next block we want
-		if (it != Cache.end() && it->Start <= Start) {
-			int64_t SrcOffset = FFMAX(0, Start - it->Start);
-			int64_t DstOffset = FFMAX(0, it->Start - Start);
-			int64_t CopySamples = FFMIN(it->Samples - SrcOffset, Count - DstOffset);
-			size_t Bytes = static_cast<size_t>(CopySamples * BytesPerSample);
-
-			memcpy(Dst + DstOffset * BytesPerSample, &it->Data[SrcOffset * BytesPerSample], Bytes);
-			Start += CopySamples;
-			Count -= CopySamples;
-			Dst += Bytes;
-			++it;
-		}
-		// Decode another block
-		else {
-			if (Start < CurrentSample && SeekOffset == -1)
-				throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_CODEC, "Audio stream is not seekable");
-
-			if (SeekOffset >= 0 && (Start < CurrentSample || Start > CurrentSample + Decoded * 5)) {
-				TFrameInfo f;
-				f.SampleStart = Start;
-				int NewPacketNumber = std::distance(Frames.begin(), std::lower_bound(Frames.begin(), Frames.end(), f, SampleStartComp));
-				NewPacketNumber = FFMAX(0, NewPacketNumber - SeekOffset - 15);
-				while (NewPacketNumber > 0 && !Frames[NewPacketNumber].KeyFrame) --NewPacketNumber;
-
-				// Only seek forward if it'll actually result in moving forward
-				if (Start < CurrentSample || static_cast<size_t>(NewPacketNumber) > PacketNumber) {
-					PacketNumber = NewPacketNumber;
-					Decoded = 0;
-					CurrentSample = -1;
-					avcodec_flush_buffers(CodecContext);
-					Seek();
-				}
-			}
-
-			// Decode everything between the last keyframe and the block we want
-			while (CurrentSample + Decoded <= Start) DecodeNextBlock();
-			if (CurrentSample > Start)
-				throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_CODEC, "Seeking is severely broken");
-
-			CacheBlock(it, CurrentSample, Decoded, &DecodingBuffer[0]);
-
-			size_t FirstSample = static_cast<size_t>(Start - CurrentSample);
-			size_t Samples = static_cast<size_t>(Decoded - FirstSample);
-			size_t Bytes = FFMIN(Samples, static_cast<size_t>(Count)) * BytesPerSample;
-
-			memcpy(Dst, &DecodingBuffer[FirstSample * BytesPerSample], Bytes);
-
-			Start += Samples;
-			Count -= Samples;
-			Dst += Bytes;
-		}
-	}
-}
-
-size_t GetSeekablePacketNumber(FFMS_Track const& Frames, size_t PacketNumber) {
-	// Packets don't always have unique PTSes, so we may not be able to
-	// uniquely identify the packet we want. This function attempts to find
-	// a PTS we can seek to which will let us figure out which packet we're
-	// on before we get to the packet we actually wanted
-
-	// MatroskaAudioSource doesn't need this, as it seeks by byte offset
-	// rather than PTS. LAVF theoretically can seek by byte offset, but we
-	// don't use it as not all demuxers support it and it's broken in some of
-	// those that claim to support it
-
-	// However much we might wish to, we can't seek to before packet zero
-	if (PacketNumber == 0) return PacketNumber;
-
-	// Desired packet's PTS is unique, so don't do anything
-	if (Frames[PacketNumber].PTS != Frames[PacketNumber - 1].PTS &&
-		(PacketNumber + 1 == Frames.size() || Frames[PacketNumber].PTS != Frames[PacketNumber + 1].PTS))
-		return PacketNumber;
-
-	// When decoding, we only reliably know what packet we're at when the
-	// newly parsed packet has a different PTS from the previous one. As such,
-	// we walk backwards until we hit a different PTS and then seek to there,
-	// so that we can then decode until we hit the PTS group we actually wanted
-	// (and thereby know that we're at the first packet in the group rather
-	// than whatever the splitter happened to choose)
-
-	// This doesn't work if our desired packet has the same PTS as the first
-	// packet, but this scenario should never come up anyway; we permanently
-	// cache the decoded results from those packets, so there's no need to ever
-	// seek to them
-	int64_t PTS = Frames[PacketNumber].PTS;
-	while (PacketNumber > 0 && PTS == Frames[PacketNumber].PTS)
-		--PacketNumber;
-	return PacketNumber;
-}
diff --git a/aegisub/libffms/src/core/audiosource.h b/aegisub/libffms/src/core/audiosource.h
deleted file mode 100644
index 3d2d8806c..000000000
--- a/aegisub/libffms/src/core/audiosource.h
+++ /dev/null
@@ -1,162 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#ifndef FFAUDIOSOURCE_H
-#define FFAUDIOSOURCE_H
-
-extern "C" {
-#include <libavformat/avformat.h>
-#include <libavcodec/avcodec.h>
-}
-
-#include <vector>
-#include <list>
-#include <memory>
-#include "indexing.h"
-#include "utils.h"
-#include "ffms.h"
-
-#ifdef HAALISOURCE
-#	define WIN32_LEAN_AND_MEAN
-#	define _WIN32_DCOM
-#	include <windows.h>
-#	include <tchar.h>
-#	include <atlbase.h>
-#	include <dshow.h>
-#	include <initguid.h>
-#	include "CoParser.h"
-#	include "guids.h"
-#endif
-
-class FFMS_AudioSource {
-	struct AudioBlock {
-		int64_t Age;
-		int64_t Start;
-		int64_t Samples;
-		std::vector<uint8_t> Data;
-
-		AudioBlock(int64_t Start, int64_t Samples, uint8_t *SrcData, size_t SrcBytes)
-			: Start(Start)
-			, Samples(Samples)
-			, Data(SrcData, SrcData + SrcBytes)
-		{
-			static int64_t Now = 0;
-			Age = Now++;
-		}
-	};
-	typedef std::list<AudioBlock>::iterator CacheIterator;
-
-	// delay in samples to apply to the audio
-	int64_t Delay;
-	// cache of decoded audio blocks
-	std::list<AudioBlock> Cache;
-	// max size of the cache in blocks
-	size_t MaxCacheBlocks;
-	// pointer to last element of the cache which should never be deleted
-	CacheIterator CacheNoDelete;
-	// bytes per sample * number of channels
-	size_t BytesPerSample;
-	// Number of samples stored in the decoding buffer
-	size_t Decoded;
-
-	// Insert a block into the cache
-	void CacheBlock(CacheIterator &pos, int64_t Start, size_t Samples, uint8_t *SrcData);
-
-	// Called after seeking
-	virtual void Seek() { };
-	// Read the next packet from the file
-	virtual bool ReadPacket(AVPacket *) = 0;
-	virtual void FreePacket(AVPacket *) { }
-protected:
-	// First sample which is stored in the decoding buffer
-	int64_t CurrentSample;
-	// Next packet to be read
-	size_t PacketNumber;
-	// Current audio frame
-	TFrameInfo *CurrentFrame;
-	// Track which this corresponds to
-	int TrackNumber;
-	// Number of packets which the demuxer requires to know where it is
-	// If -1, seeking is assumed to be impossible
-	int SeekOffset;
-
-	// Buffer which audio is decoded into
-	AlignedBuffer<uint8_t> DecodingBuffer;
-	FFMS_Track Frames;
-	FFCodecContext CodecContext;
-	FFMS_AudioProperties AP;
-
-	void DecodeNextBlock();
-	// Initialization which has to be done after the codec is opened
-	void Init(FFMS_Index &Index, int DelayMode);
-
-	FFMS_AudioSource(const char *SourceFile, FFMS_Index &Index, int Track);
-
-public:
-	virtual ~FFMS_AudioSource() { };
-	FFMS_Track *GetTrack() { return &Frames; }
-	const FFMS_AudioProperties& GetAudioProperties() const { return AP; }
-	void GetAudio(void *Buf, int64_t Start, int64_t Count);
-};
-
-class FFLAVFAudio : public FFMS_AudioSource {
-	AVFormatContext *FormatContext;
-
-	bool ReadPacket(AVPacket *);
-	void FreePacket(AVPacket *);
-	void Seek();
-
-public:
-	FFLAVFAudio(const char *SourceFile, int Track, FFMS_Index &Index, int DelayMode);
-	~FFLAVFAudio();
-};
-
-class FFMatroskaAudio : public FFMS_AudioSource {
-	MatroskaFile *MF;
-	MatroskaReaderContext MC;
-	TrackInfo *TI;
-	std::auto_ptr<TrackCompressionContext> TCC;
-	char ErrorMessage[256];
-
-	bool ReadPacket(AVPacket *);
-
-public:
-	FFMatroskaAudio(const char *SourceFile, int Track, FFMS_Index &Index, int DelayMode);
-	~FFMatroskaAudio();
-};
-
-#ifdef HAALISOURCE
-
-class FFHaaliAudio : public FFMS_AudioSource {
-	CComPtr<IMMContainer> pMMC;
-	CComPtr<IMMFrame> pMMF;
-
-	bool ReadPacket(AVPacket *);
-	void Seek();
-
-public:
-	FFHaaliAudio(const char *SourceFile, int Track, FFMS_Index &Index, enum FFMS_Sources SourceMode, int DelayMode);
-};
-
-#endif // HAALISOURCE
-
-size_t GetSeekablePacketNumber(FFMS_Track const& Frames, size_t PacketNumber);
-
-#endif
diff --git a/aegisub/libffms/src/core/config.h b/aegisub/libffms/src/core/config.h
deleted file mode 100644
index e69de29bb..000000000
diff --git a/aegisub/libffms/src/core/ffms.cpp b/aegisub/libffms/src/core/ffms.cpp
deleted file mode 100644
index 57a49b2aa..000000000
--- a/aegisub/libffms/src/core/ffms.cpp
+++ /dev/null
@@ -1,469 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include <sstream>
-#include <iomanip>
-#include "ffms.h"
-#include "videosource.h"
-#include "audiosource.h"
-#include "indexing.h"
-
-extern "C" {
-#include <libavutil/pixdesc.h>
-}
-
-
-#ifdef FFMS_WIN_DEBUG
-#	include <windows.h>
-#endif
-
-static bool FFmpegInited	= false;
-bool HasHaaliMPEG = false;
-bool HasHaaliOGG = false;
-int CPUFeatures = 0;
-bool GlobalUseUTF8Paths = false;
-
-
-#ifdef FFMS_WIN_DEBUG
-
-extern "C" int av_log_level;
-
-void av_log_windebug_callback(void* ptr, int level, const char* fmt, va_list vl) {
-	static int print_prefix=1;
-	static int count;
-	static char line[1024] = {0}, prev[1024] = {0};
-	AVClass* avc = ptr ? *(AVClass**)ptr : NULL;
-	if(level > av_log_level)
-		return;
-
-	int written = 0;
-	if(print_prefix && avc) {
-		written = snprintf(line, sizeof(line), "[%s @ %p]", avc->item_name(ptr), ptr);
-	}
-
-	written += vsnprintf(line + written, sizeof(line) - written, fmt, vl);
-
-	print_prefix = line[written-1] == '\n';
-	line[sizeof(line) - 1] = 0;
-	if(print_prefix && !strcmp(line, prev)){
-		count++;
-		return;
-	}
-	if(count > 0){
-		std::stringstream ss;
-		ss << "    Last message repeated " << count << " times\n";
-		OutputDebugStringA(ss.str().c_str());
-		count = 0;
-	}
-	OutputDebugStringA(line);
-	strcpy(prev, line);
-}
-
-#endif
-
-FFMS_API(void) FFMS_Init(int CPUFeatures, int UseUTF8Paths) {
-	if (!FFmpegInited) {
-		av_register_all();
-#ifdef _WIN32
-		if (UseUTF8Paths) {
-			ffms_patch_lavf_file_open();
-			GlobalUseUTF8Paths = true;
-		}
-		else {
-			GlobalUseUTF8Paths = false;
-		}
-#else
-		GlobalUseUTF8Paths = false;
-#endif
-#ifdef FFMS_WIN_DEBUG
-		av_log_set_callback(av_log_windebug_callback);
-		av_log_set_level(AV_LOG_INFO);
-#else
-		av_log_set_level(AV_LOG_QUIET);
-#endif
-		::CPUFeatures = CPUFeatures;
-#ifdef HAALISOURCE
-		CComPtr<IMMContainer> pMMC;
-		HasHaaliMPEG = !FAILED(pMMC.CoCreateInstance(HAALI_MPEG_PARSER));
-		pMMC = NULL;
-		HasHaaliOGG = !FAILED(pMMC.CoCreateInstance(HAALI_OGG_PARSER));
-		pMMC = NULL;
-#endif
-		FFmpegInited = true;
-	}
-}
-
-FFMS_API(int) FFMS_GetLogLevel() {
-	return av_log_get_level();
-}
-
-FFMS_API(void) FFMS_SetLogLevel(int Level) {
-	av_log_set_level(Level);
-}
-
-FFMS_API(FFMS_VideoSource *) FFMS_CreateVideoSource(const char *SourceFile, int Track, FFMS_Index *Index, int Threads, int SeekMode, FFMS_ErrorInfo *ErrorInfo) {
-	if (Threads < 1)
-		Threads = 1;
-	try {
-		switch (Index->Decoder) {
-			case FFMS_SOURCE_LAVF:
-				return new FFLAVFVideo(SourceFile, Track, Index, Threads, SeekMode);
-			case FFMS_SOURCE_MATROSKA:
-				return new FFMatroskaVideo(SourceFile, Track, Index, Threads);
-#ifdef HAALISOURCE
-			case FFMS_SOURCE_HAALIMPEG:
-				if (HasHaaliMPEG)
-					return new FFHaaliVideo(SourceFile, Track, Index, Threads, FFMS_SOURCE_HAALIMPEG);
-				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_NOT_AVAILABLE, "Haali MPEG/TS source unavailable");
-			case FFMS_SOURCE_HAALIOGG:
-				if (HasHaaliOGG)
-					return new FFHaaliVideo(SourceFile, Track, Index, Threads, FFMS_SOURCE_HAALIOGG);
-				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_NOT_AVAILABLE, "Haali OGG/OGM source unavailable");
-#endif
-			default: 
-				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, "Unsupported format");
-		}
-	} catch (FFMS_Exception &e) {
-		e.CopyOut(ErrorInfo);
-		return NULL;
-	}
-}
-
-FFMS_API(FFMS_AudioSource *) FFMS_CreateAudioSource(const char *SourceFile, int Track, FFMS_Index *Index, int DelayMode, FFMS_ErrorInfo *ErrorInfo) {
-	try {
-		switch (Index->Decoder) {
-			case FFMS_SOURCE_LAVF:
-				return new FFLAVFAudio(SourceFile, Track, *Index, DelayMode);
-			case FFMS_SOURCE_MATROSKA:
-				return new FFMatroskaAudio(SourceFile, Track, *Index, DelayMode);
-#ifdef HAALISOURCE
-			case FFMS_SOURCE_HAALIMPEG:
-				if (HasHaaliMPEG)
-					return new FFHaaliAudio(SourceFile, Track, *Index, FFMS_SOURCE_HAALIMPEG, DelayMode);
-				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_NOT_AVAILABLE, "Haali MPEG/TS source unavailable");
-			case FFMS_SOURCE_HAALIOGG:
-				if (HasHaaliOGG)
-					return new FFHaaliAudio(SourceFile, Track, *Index, FFMS_SOURCE_HAALIOGG, DelayMode);
-				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_NOT_AVAILABLE, "Haali OGG/OGM source unavailable");
-#endif
-			default: 
-				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, "Unsupported format");
-		}
-	} catch (FFMS_Exception &e) {
-		e.CopyOut(ErrorInfo);
-		return NULL;
-	}
-}
-
-FFMS_API(void) FFMS_DestroyVideoSource(FFMS_VideoSource *V) {
-	delete V;
-}
-
-FFMS_API(void) FFMS_DestroyAudioSource(FFMS_AudioSource *A) {
-	delete A;
-}
-
-FFMS_API(const FFMS_VideoProperties *) FFMS_GetVideoProperties(FFMS_VideoSource *V) {
-	return &V->GetVideoProperties();
-}
-
-FFMS_API(const FFMS_AudioProperties *) FFMS_GetAudioProperties(FFMS_AudioSource *A) {
-	return &A->GetAudioProperties();
-}
-
-FFMS_API(const FFMS_Frame *) FFMS_GetFrame(FFMS_VideoSource *V, int n, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-	try {
-		return V->GetFrame(n);
-	} catch (FFMS_Exception &e) {
-		e.CopyOut(ErrorInfo);
-		return NULL;
-	}
-}
-
-FFMS_API(const FFMS_Frame *) FFMS_GetFrameByTime(FFMS_VideoSource *V, double Time, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-	try {
-		return (FFMS_Frame *)V->GetFrameByTime(Time);
-	} catch (FFMS_Exception &e) {
-		e.CopyOut(ErrorInfo);
-		return NULL;
-	}
-}
-
-FFMS_API(int) FFMS_GetAudio(FFMS_AudioSource *A, void *Buf, int64_t Start, int64_t Count, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-	try {
-		A->GetAudio(Buf, Start, Count);
-	} catch (FFMS_Exception &e) {
-		return e.CopyOut(ErrorInfo);
-	}
-	return FFMS_ERROR_SUCCESS;
-}
-
-FFMS_API(int) FFMS_SetOutputFormatV(FFMS_VideoSource *V, int64_t TargetFormats, int Width, int Height, int Resizer, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-	try {
-		V->SetOutputFormat(TargetFormats, Width, Height, Resizer);
-	} catch (FFMS_Exception &e) {
-		return e.CopyOut(ErrorInfo);
-	}
-	return FFMS_ERROR_SUCCESS;
-}
-
-FFMS_API(void) FFMS_ResetOutputFormatV(FFMS_VideoSource *V) {
-	V->ResetOutputFormat();
-}
-
-FFMS_API(int) FFMS_SetPP(FFMS_VideoSource *V, const char *PP, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-	try {
-		V->SetPP(PP);
-	} catch (FFMS_Exception &e) {
-		return e.CopyOut(ErrorInfo);
-	}
-	return FFMS_ERROR_SUCCESS;
-}
-
-FFMS_API(void) FFMS_ResetPP(FFMS_VideoSource *V) {
-	V->ResetPP();
-}
-
-FFMS_API(void) FFMS_DestroyIndex(FFMS_Index *Index) {
-	delete Index;
-}
-
-FFMS_API(int) FFMS_GetSourceType(FFMS_Index *Index) {
-	return Index->Decoder;
-}
-
-FFMS_API(int) FFMS_GetFirstTrackOfType(FFMS_Index *Index, int TrackType, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-	for (int i = 0; i < static_cast<int>(Index->size()); i++)
-		if ((*Index)[i].TT == TrackType)
-			return i;
-	
-	try {
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_NOT_AVAILABLE,
-			"No suitable, indexed track found");
-	} catch (FFMS_Exception &e) {
-		e.CopyOut(ErrorInfo);
-		return -1;
-	}
-}
-
-FFMS_API(int) FFMS_GetFirstIndexedTrackOfType(FFMS_Index *Index, int TrackType, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-	for (int i = 0; i < static_cast<int>(Index->size()); i++)
-		if ((*Index)[i].TT == TrackType && (*Index)[i].size() > 0)
-			return i;
-	try {
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_NOT_AVAILABLE,
-			"No suitable, indexed track found");
-	} catch (FFMS_Exception &e) {
-		e.CopyOut(ErrorInfo);
-		return -1;
-	}
-}
-
-FFMS_API(int) FFMS_GetNumTracks(FFMS_Index *Index) {
-	return Index->size();
-}
-
-FFMS_API(int) FFMS_GetNumTracksI(FFMS_Indexer *Indexer) {
-	return Indexer->GetNumberOfTracks();
-}
-
-FFMS_API(int) FFMS_GetTrackType(FFMS_Track *T) {
-	return T->TT;
-}
-
-FFMS_API(int) FFMS_GetTrackTypeI(FFMS_Indexer *Indexer, int Track) {
-	return Indexer->GetTrackType(Track);
-}
-
-FFMS_API(const char *) FFMS_GetCodecNameI(FFMS_Indexer *Indexer, int Track) {
-	return Indexer->GetTrackCodec(Track);
-}
-
-FFMS_API(int) FFMS_GetNumFrames(FFMS_Track *T) {
-	return T->size();
-}
-
-FFMS_API(const FFMS_FrameInfo *) FFMS_GetFrameInfo(FFMS_Track *T, int Frame) {
-	return reinterpret_cast<FFMS_FrameInfo *>(&(*T)[Frame]);
-}
-
-FFMS_API(FFMS_Track *) FFMS_GetTrackFromIndex(FFMS_Index *Index, int Track) {
-	return &(*Index)[Track];
-}
-
-FFMS_API(FFMS_Track *) FFMS_GetTrackFromVideo(FFMS_VideoSource *V) {
-	return V->GetTrack();
-}
-
-FFMS_API(FFMS_Track *) FFMS_GetTrackFromAudio(FFMS_AudioSource *A) {
-	return A->GetTrack();
-}
-
-FFMS_API(const FFMS_TrackTimeBase *) FFMS_GetTimeBase(FFMS_Track *T) {
-	return &T->TB;
-}
-
-FFMS_API(int) FFMS_WriteTimecodes(FFMS_Track *T, const char *TimecodeFile, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-	try {
-		T->WriteTimecodes(TimecodeFile);
-	} catch (FFMS_Exception &e) {
-		return e.CopyOut(ErrorInfo);
-	}
-	return FFMS_ERROR_SUCCESS;
-}
-
-FFMS_API(FFMS_Index *) FFMS_MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, int ErrorHandling, TIndexCallback IC, void *ICPrivate, FFMS_ErrorInfo *ErrorInfo) {
-	FFMS_Indexer *Indexer = FFMS_CreateIndexer(SourceFile, ErrorInfo);
-	if (!Indexer)
-		return NULL;
-	return FFMS_DoIndexing(Indexer, IndexMask, DumpMask, ANC, ANCPrivate, ErrorHandling, IC, ICPrivate, ErrorInfo);
-}
-
-/* Used by FFMS_DefaultAudioFilename */ 
-
-static std::string IntToStr(int i, int zp = 0) {
-	std::stringstream s;
-	s.fill('0');
-	s.width(zp);
-	s << i;
-	return s.str();
-}
-
-static void ReplaceString(std::string &s, std::string from, std::string to) {
-	int idx;
-	while ((idx = s.find(from)) != std::string::npos)
-		s.replace(idx, from.length(), to);
-}
-
-FFMS_API(int) FFMS_DefaultAudioFilename(const char *SourceFile, int Track, const FFMS_AudioProperties *AP, char *FileName, int FNSize, void *Private) {
-	std::string s = static_cast<char *>(Private);
-
-	ReplaceString(s, "%sourcefile%", SourceFile);
-	ReplaceString(s, "%trackn%", IntToStr(Track));
-	ReplaceString(s, "%trackzn%", IntToStr(Track, 2));
-	ReplaceString(s, "%samplerate%", IntToStr(AP->SampleRate));
-	ReplaceString(s, "%channels%", IntToStr(AP->Channels));
-	ReplaceString(s, "%bps%", IntToStr(AP->BitsPerSample));
-	ReplaceString(s, "%delay%", IntToStr(static_cast<int>(AP->FirstTime)));
-	
-	if (FileName != NULL)
-		strcpy(FileName, s.c_str());
-
-	return s.length() + 1;
-}
-
-FFMS_API(FFMS_Indexer *) FFMS_CreateIndexer(const char *SourceFile, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-	try {
-		return FFMS_Indexer::CreateIndexer(SourceFile);
-	} catch (FFMS_Exception &e) {
-		e.CopyOut(ErrorInfo);
-		return NULL;
-	}
-}
-
-FFMS_API(FFMS_Index *) FFMS_DoIndexing(FFMS_Indexer *Indexer, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, int ErrorHandling, TIndexCallback IC, void *ICPrivate, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-
-	Indexer->SetIndexMask(IndexMask | DumpMask);
-	Indexer->SetDumpMask(DumpMask);
-	Indexer->SetErrorHandling(ErrorHandling);
-	Indexer->SetProgressCallback(IC, ICPrivate);
-	Indexer->SetAudioNameCallback(ANC, ANCPrivate);
-
-	FFMS_Index *Index = NULL;
-	try {
-		Index = Indexer->DoIndexing();
-	} catch (FFMS_Exception &e) {
-		e.CopyOut(ErrorInfo);
-	}
-	delete Indexer;
-	return Index;
-}
-
-FFMS_API(void) FFMS_CancelIndexing(FFMS_Indexer *Indexer) {
-	delete Indexer;
-}
-
-FFMS_API(FFMS_Index *) FFMS_ReadIndex(const char *IndexFile, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-	FFMS_Index *Index = new FFMS_Index();
-	try {
-		Index->ReadIndex(IndexFile);
-	} catch (FFMS_Exception &e) {
-		delete Index;
-		e.CopyOut(ErrorInfo);
-		return NULL;
-	}
-	return Index;
-}
-
-FFMS_API(int) FFMS_IndexBelongsToFile(FFMS_Index *Index, const char *SourceFile, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-	try {
-		if (!Index->CompareFileSignature(SourceFile))
-			throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_MISMATCH,
-				"The index does not belong to the file");
-	} catch (FFMS_Exception &e) {
-		return e.CopyOut(ErrorInfo);
-	}
-	return FFMS_ERROR_SUCCESS;
-}
-
-FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FFMS_Index *Index, FFMS_ErrorInfo *ErrorInfo) {
-	ClearErrorInfo(ErrorInfo);
-	try {
-		Index->WriteIndex(IndexFile);
-	} catch (FFMS_Exception &e) {
-		return e.CopyOut(ErrorInfo);
-	}
-	return FFMS_ERROR_SUCCESS;
-}
-
-FFMS_API(int) FFMS_GetPixFmt(const char *Name) {
-	return av_get_pix_fmt(Name);
-}
-
-FFMS_API(int) FFMS_GetPresentSources() {
-	int Sources = FFMS_SOURCE_LAVF | FFMS_SOURCE_MATROSKA;
-#ifdef HAALISOURCE
-	Sources |= FFMS_SOURCE_HAALIMPEG | FFMS_SOURCE_HAALIOGG;
-#endif
-	return Sources;
-}
-
-FFMS_API(int) FFMS_GetEnabledSources() {
-	if (!FFmpegInited)
-		return 0;
-	int Sources = FFMS_SOURCE_LAVF | FFMS_SOURCE_MATROSKA;
-	if (HasHaaliMPEG)
-		Sources |= FFMS_SOURCE_HAALIMPEG;
-	if (HasHaaliOGG)
-		Sources |= FFMS_SOURCE_HAALIOGG;
-	return Sources;
-}
diff --git a/aegisub/libffms/src/core/indexing.cpp b/aegisub/libffms/src/core/indexing.cpp
deleted file mode 100644
index 150bf4464..000000000
--- a/aegisub/libffms/src/core/indexing.cpp
+++ /dev/null
@@ -1,603 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include "indexing.h"
-
-#include <algorithm>
-#include <fstream>
-#include <iostream>
-#include <limits>
-
-
-extern "C" {
-#include <libavutil/sha1.h>
-#include <zlib.h>
-}
-
-#undef max
-
-#define INDEXID 0x53920873
-
-extern bool HasHaaliMPEG;
-extern bool HasHaaliOGG;
-
-#ifndef FFMS_USE_POSTPROC
-unsigned postproc_version() { return 0; } // ugly workaround to avoid lots of ifdeffing
-#endif // FFMS_USE_POSTPROC
-
-struct IndexHeader {
-	uint32_t Id;
-	uint32_t Version;
-	uint32_t Tracks;
-	uint32_t Decoder;
-	uint32_t LAVUVersion;
-	uint32_t LAVFVersion;
-	uint32_t LAVCVersion;
-	uint32_t LSWSVersion;
-	uint32_t LPPVersion;
-	int64_t FileSize;
-	uint8_t FileSignature[20];
-};
-
-struct TrackHeader {
-	uint32_t TT;
-	uint32_t Frames;
-	int64_t Num;
-	int64_t Den;
-	uint32_t UseDTS;
-};
-
-
-SharedVideoContext::SharedVideoContext(bool FreeCodecContext) {
-	CodecContext = NULL;
-	Parser = NULL;
-	this->FreeCodecContext = FreeCodecContext;
-	TCC = NULL;
-}
-
-SharedVideoContext::~SharedVideoContext() {
-	if (CodecContext) {
-		avcodec_close(CodecContext);
-		if (FreeCodecContext)
-			av_freep(&CodecContext);
-	}
-	av_parser_close(Parser);
-	delete TCC;
-}
-
-SharedAudioContext::SharedAudioContext(bool FreeCodecContext) {
-	W64Writer = NULL;
-	CodecContext = NULL;
-	CurrentSample = 0;
-	TCC = NULL;
-	this->FreeCodecContext = FreeCodecContext;
-}
-
-SharedAudioContext::~SharedAudioContext() {
-	delete W64Writer;
-	if (CodecContext) {
-		avcodec_close(CodecContext);
-		if (FreeCodecContext)
-			av_freep(&CodecContext);
-	}
-	delete TCC;
-}
-
-TFrameInfo::TFrameInfo() {
-}
-
-TFrameInfo::TFrameInfo(int64_t PTS, int64_t SampleStart, unsigned int SampleCount, int RepeatPict, bool KeyFrame, int64_t FilePos, unsigned int FrameSize) {
-	this->PTS = PTS;
-	this->RepeatPict = RepeatPict;
-	this->KeyFrame = KeyFrame;
-	this->SampleStart = SampleStart;
-	this->SampleCount = SampleCount;
-	this->FilePos = FilePos;
-	this->FrameSize = FrameSize;
-	this->OriginalPos = 0;
-}
-
-TFrameInfo TFrameInfo::VideoFrameInfo(int64_t PTS, int RepeatPict, bool KeyFrame, int64_t FilePos, unsigned int FrameSize) {
-	return TFrameInfo(PTS, 0, 0, RepeatPict, KeyFrame, FilePos, FrameSize);
-}
-
-TFrameInfo TFrameInfo::AudioFrameInfo(int64_t PTS, int64_t SampleStart, int64_t SampleCount, bool KeyFrame, int64_t FilePos, unsigned int FrameSize) {
-	return TFrameInfo(PTS, SampleStart, static_cast<unsigned int>(SampleCount), 0, KeyFrame, FilePos, FrameSize);
-}
-
-void FFMS_Track::WriteTimecodes(const char *TimecodeFile) {
-	ffms_fstream Timecodes(TimecodeFile, std::ios::out | std::ios::trunc);
-
-	if (!Timecodes.is_open())
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			std::string("Failed to open '") + TimecodeFile + "' for writing");
-
-	Timecodes << "# timecode format v2\n";
-
-	for (iterator Cur = begin(); Cur != end(); ++Cur)
-		Timecodes << std::fixed << ((Cur->PTS * TB.Num) / (double)TB.Den) << "\n";
-}
-
-int FFMS_Track::FrameFromPTS(int64_t PTS) {
-	for (int i = 0; i < static_cast<int>(size()); i++)
-		if (at(i).PTS == PTS)
-			return i;
-	return -1;
-}
-
-static bool PTSComparison(TFrameInfo FI1, TFrameInfo FI2) {
-	return FI1.PTS < FI2.PTS;
-}
-
-int FFMS_Track::ClosestFrameFromPTS(int64_t PTS) {
-	TFrameInfo F;
-	F.PTS = PTS;
-
-	iterator Pos = std::lower_bound(begin(), end(), F, PTSComparison);
-	int Frame = std::distance(begin(), Pos);
-	if ((Pos + 1) != end() && FFABS(Pos->PTS - PTS) > FFABS((Pos + 1)->PTS - PTS))
-		Frame += 1;
-	return Frame;
-}
-
-int FFMS_Track::FindClosestVideoKeyFrame(int Frame) {
-	Frame = FFMIN(FFMAX(Frame, 0), static_cast<int>(size()) - 1);
-	for (; Frame > 0 && !at(Frame).KeyFrame; Frame--) ;
-	for (; Frame > 0 && !at(at(Frame).OriginalPos).KeyFrame; Frame--) ;
-	return Frame;
-}
-
-FFMS_Track::FFMS_Track() {
-	this->TT = FFMS_TYPE_UNKNOWN;
-	this->TB.Num = 0;
-	this->TB.Den = 0;
-	this->UseDTS = false;
-}
-
-FFMS_Track::FFMS_Track(int64_t Num, int64_t Den, FFMS_TrackType TT, bool UseDTS) {
-	this->TT = TT;
-	this->TB.Num = Num;
-	this->TB.Den = Den;
-	this->UseDTS = UseDTS;
-}
-
-void FFMS_Index::CalculateFileSignature(const char *Filename, int64_t *Filesize, uint8_t Digest[20]) {
-	FILE *SFile = ffms_fopen(Filename,"rb");
-	if (!SFile)
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			std::string("Failed to open '") + Filename + "' for hashing");
-
-	std::vector<uint8_t> FileBuffer(1024*1024, 0);
-	std::vector<uint8_t> ctxmem(av_sha1_size);
-	AVSHA1 *ctx = (AVSHA1 *)(&ctxmem[0]);
-	av_sha1_init(ctx);
-
-	try {
-		fread(&FileBuffer[0], 1, FileBuffer.size(), SFile);
-		if (ferror(SFile) && !feof(SFile))
-			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-				std::string("Failed to read '") + Filename + "' for hashing");
-
-		av_sha1_update(ctx, &FileBuffer[0], FileBuffer.size());
-
-		fseeko(SFile, -(int)FileBuffer.size(), SEEK_END);
-		std::fill(FileBuffer.begin(), FileBuffer.end(), 0);
-		fread(&FileBuffer[0], 1, FileBuffer.size(), SFile);
-		if (ferror(SFile) && !feof(SFile)) {
-			std::ostringstream buf;
-			buf << "Failed to seek with offset " << FileBuffer.size() << " from file end in '" << Filename << "' for hashing";
-			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, buf.str());
-		}
-
-		av_sha1_update(ctx, &FileBuffer[0], FileBuffer.size());
-
-		fseeko(SFile, 0, SEEK_END);
-		if (ferror(SFile))
-			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-				std::string("Failed to seek to end of '") + Filename + "' for hashing");
-
-		*Filesize = ftello(SFile);
-	}
-	catch (...) {
-		fclose(SFile);
-		av_sha1_final(ctx, Digest);
-		throw;
-	}
-	fclose(SFile);
-	av_sha1_final(ctx, Digest);
-}
-
-void FFMS_Index::Sort() {
-	for (FFMS_Index::iterator Cur = begin(); Cur != end(); ++Cur) {
-		if (Cur->size() > 2 && Cur->front().PTS >= Cur->back().PTS) Cur->pop_back();
-
-		for (size_t i = 0; i < Cur->size(); i++)
-			Cur->at(i).OriginalPos = i;
-
-		std::sort(Cur->begin(), Cur->end(), PTSComparison);
-
-		std::vector<size_t> ReorderTemp;
-		ReorderTemp.resize(Cur->size());
-
-		for (size_t i = 0; i < Cur->size(); i++)
-			ReorderTemp[i] = Cur->at(i).OriginalPos;
-
-		for (size_t i = 0; i < Cur->size(); i++)
-			Cur->at(ReorderTemp[i]).OriginalPos = i;
-	}
-}
-
-bool FFMS_Index::CompareFileSignature(const char *Filename) {
-	int64_t CFilesize;
-	uint8_t CDigest[20];
-	CalculateFileSignature(Filename, &CFilesize, CDigest);
-	return (CFilesize == Filesize && !memcmp(CDigest, Digest, sizeof(Digest)));
-}
-
-#define CHUNK 65536
-
-static unsigned int z_def(ffms_fstream *IndexStream, z_stream *stream, void *in, size_t in_sz, int finish) {
-	unsigned int total = 0, have;
-	int ret;
-	char out[CHUNK];
-
-	if (!finish && (in_sz == 0 || in == NULL)) return 0;
-
-	stream->next_in = (Bytef*) in;
-	stream->avail_in = in_sz;
-	do {
-		do {
-			stream->avail_out = CHUNK;
-			stream->next_out = (Bytef*) out;
-			ret = deflate(stream, finish ? Z_FINISH : Z_NO_FLUSH);
-			have = CHUNK - stream->avail_out;
-			if (have) IndexStream->write(out, have);
-			total += have;
-		} while (stream->avail_out == 0);
-	} while (finish && ret != Z_STREAM_END);
-	if (finish) deflateEnd(stream);
-	return total;
-}
-
-void FFMS_Index::WriteIndex(const char *IndexFile) {
-	ffms_fstream IndexStream(IndexFile, std::ios::out | std::ios::binary | std::ios::trunc);
-
-	if (!IndexStream.is_open())
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			std::string("Failed to open '") + IndexFile + "' for writing");
-
-	z_stream stream;
-	memset(&stream, 0, sizeof(z_stream));
-	if (deflateInit(&stream, 9) != Z_OK) {
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, "Failed to initialize zlib");
-	}
-
-	// Write the index file header
-	IndexHeader IH;
-	IH.Id = INDEXID;
-	IH.Version = FFMS_VERSION;
-	IH.Tracks = size();
-	IH.Decoder = Decoder;
-	IH.LAVUVersion = avutil_version();
-	IH.LAVFVersion = avformat_version();
-	IH.LAVCVersion = avcodec_version();
-	IH.LSWSVersion = swscale_version();
-	IH.LPPVersion = postproc_version();
-	IH.FileSize = Filesize;
-	memcpy(IH.FileSignature, Digest, sizeof(Digest));
-
-	z_def(&IndexStream, &stream, &IH, sizeof(IndexHeader), 0);
-
-	for (unsigned int i = 0; i < IH.Tracks; i++) {
-		FFMS_Track &ctrack = at(i);
-		TrackHeader TH;
-		TH.TT = ctrack.TT;
-		TH.Frames = ctrack.size();
-		TH.Num = ctrack.TB.Num;;
-		TH.Den = ctrack.TB.Den;
-		TH.UseDTS = ctrack.UseDTS;
-
-		FFMS_Track temptrack;
-		temptrack.resize(TH.Frames);
-
-		if (TH.Frames)
-			temptrack[0] = ctrack[0];
-
-		for (size_t j = 1; j < ctrack.size(); j++) {
-			temptrack[j] = ctrack[j];
-			temptrack[j].FilePos = ctrack[j].FilePos - ctrack[j - 1].FilePos;
-			temptrack[j].OriginalPos = ctrack[j].OriginalPos - ctrack[j - 1].OriginalPos;
-			temptrack[j].PTS = ctrack[j].PTS - ctrack[j - 1].PTS;
-			temptrack[j].SampleStart = ctrack[j].SampleStart - ctrack[j - 1].SampleStart;
-		}
-
-		z_def(&IndexStream, &stream, &TH, sizeof(TrackHeader), 0);
-		if (TH.Frames)
-			z_def(&IndexStream, &stream, FFMS_GET_VECTOR_PTR(temptrack), TH.Frames * sizeof(TFrameInfo), 0);
-	}
-	z_def(&IndexStream, &stream, NULL, 0, 1);
-}
-
-static unsigned int z_inf(ffms_fstream *Index, z_stream *stream, void *in, size_t in_sz, void *out, size_t out_sz) {
-	if (out_sz == 0 || out == 0) return 0;
-	stream->next_out = (Bytef*) out;
-	stream->avail_out = out_sz;
-
-	do {
-		if (stream->avail_in) memmove(in, stream->next_in, stream->avail_in);
-		Index->read(((char*)in) + stream->avail_in, in_sz - stream->avail_in);
-		stream->next_in = (Bytef*) in;
-		stream->avail_in += Index->gcount();
-
-		switch (inflate(stream, Z_SYNC_FLUSH)) {
-		case Z_NEED_DICT:
-			inflateEnd(stream);
-			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, "Failed to read data: Dictionary error.");
-		case Z_DATA_ERROR:
-			inflateEnd(stream);
-			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, "Failed to read data: Data error.");
-		case Z_MEM_ERROR:
-			inflateEnd(stream);
-			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, "Failed to read data: Memory error.");
-		case Z_STREAM_END:
-			inflateEnd(stream);
-			return out_sz - stream->avail_out;
-		}
-
-	} while (stream->avail_out);
-	return out_sz;
-}
-
-void FFMS_Index::ReadIndex(const char *IndexFile) {
-	ffms_fstream Index(IndexFile, std::ios::in | std::ios::binary);
-
-	if (!Index.is_open())
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			std::string("Failed to open '") + IndexFile + "' for reading");
-
-	z_stream stream;
-	memset(&stream, 0, sizeof(z_stream));
-	unsigned char in[CHUNK];
-	if (inflateInit(&stream) != Z_OK)
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			"Failed to initialize zlib");
-
-	// Read the index file header
-	IndexHeader IH;
-	z_inf(&Index, &stream,  &in, CHUNK, &IH, sizeof(IndexHeader));
-
-	if (IH.Id != INDEXID)
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			std::string("'") + IndexFile + "' is not a valid index file");
-
-	if (IH.Version != FFMS_VERSION)
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			std::string("'") + IndexFile + "' is the expected index version");
-
-	if (IH.LAVUVersion != avutil_version() || IH.LAVFVersion != avformat_version() ||
-		IH.LAVCVersion != avcodec_version() || IH.LSWSVersion != swscale_version() ||
-		IH.LPPVersion != postproc_version())
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			std::string("A different FFmpeg build was used to create '") + IndexFile + "'");
-
-	if (!(IH.Decoder & FFMS_GetEnabledSources()))
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_NOT_AVAILABLE,
-			"The source which this index was created with is not available");
-
-	Decoder = IH.Decoder;
-	Filesize = IH.FileSize;
-	memcpy(Digest, IH.FileSignature, sizeof(Digest));
-
-	try {
-		for (unsigned int i = 0; i < IH.Tracks; i++) {
-			TrackHeader TH;
-			z_inf(&Index, &stream, &in, CHUNK, &TH, sizeof(TrackHeader));
-			push_back(FFMS_Track(TH.Num, TH.Den, static_cast<FFMS_TrackType>(TH.TT), TH.UseDTS != 0));
-			FFMS_Track &ctrack = at(i);
-
-			if (TH.Frames) {
-				ctrack.resize(TH.Frames);
-				z_inf(&Index, &stream, &in, CHUNK, FFMS_GET_VECTOR_PTR(ctrack), TH.Frames * sizeof(TFrameInfo));
-			}
-
-			for (size_t j = 1; j < ctrack.size(); j++) {
-				ctrack[j].FilePos = ctrack[j].FilePos + ctrack[j - 1].FilePos;
-				ctrack[j].OriginalPos = ctrack[j].OriginalPos + ctrack[j - 1].OriginalPos;
-				ctrack[j].PTS = ctrack[j].PTS + ctrack[j - 1].PTS;
-				ctrack[j].SampleStart = ctrack[j].SampleStart + ctrack[j - 1].SampleStart;
-			}
-		}
-	}
-	catch (FFMS_Exception const&) {
-		throw;
-	}
-	catch (...) {
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			std::string("Unknown error while reading index information in '") + IndexFile + "'");
-	}
-}
-
-FFMS_Index::FFMS_Index() {
-}
-
-FFMS_Index::FFMS_Index(int64_t Filesize, uint8_t Digest[20]) {
-	this->Filesize = Filesize;
-	memcpy(this->Digest, Digest, sizeof(this->Digest));
-}
-
-void FFMS_Indexer::SetIndexMask(int IndexMask) {
-	this->IndexMask = IndexMask;
-}
-
-void FFMS_Indexer::SetDumpMask(int DumpMask) {
-	this->DumpMask = DumpMask;
-}
-
-void FFMS_Indexer::SetErrorHandling(int ErrorHandling) {
-	if (ErrorHandling != FFMS_IEH_ABORT && ErrorHandling != FFMS_IEH_CLEAR_TRACK &&
-		ErrorHandling != FFMS_IEH_STOP_TRACK && ErrorHandling != FFMS_IEH_IGNORE)
-		throw FFMS_Exception(FFMS_ERROR_INDEXING, FFMS_ERROR_INVALID_ARGUMENT,
-			"Invalid error handling mode specified");
-	this->ErrorHandling = ErrorHandling;
-}
-
-void FFMS_Indexer::SetProgressCallback(TIndexCallback IC, void *ICPrivate) {
-	this->IC = IC;
-	this->ICPrivate = ICPrivate;
-}
-
-void FFMS_Indexer::SetAudioNameCallback(TAudioNameCallback ANC, void *ANCPrivate) {
-	this->ANC = ANC;
-	this->ANCPrivate = ANCPrivate;
-}
-
-FFMS_Indexer *FFMS_Indexer::CreateIndexer(const char *Filename) {
-	AVFormatContext *FormatContext = NULL;
-
-	if (av_open_input_file(&FormatContext, Filename, NULL, 0, NULL) != 0)
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			std::string("Can't open '") + Filename + "'");
-
-	// Do matroska indexing instead?
-	if (!strncmp(FormatContext->iformat->name, "matroska", 8)) {
-		av_close_input_file(FormatContext);
-		return new FFMatroskaIndexer(Filename);
-	}
-
-#ifdef HAALISOURCE
-	// Do haali ts indexing instead?
-	if (HasHaaliMPEG && (!strcmp(FormatContext->iformat->name, "mpeg") || !strcmp(FormatContext->iformat->name, "mpegts"))) {
-		av_close_input_file(FormatContext);
-		return new FFHaaliIndexer(Filename, FFMS_SOURCE_HAALIMPEG);
-	}
-
-	if (HasHaaliOGG && !strcmp(FormatContext->iformat->name, "ogg")) {
-		av_close_input_file(FormatContext);
-		return new FFHaaliIndexer(Filename, FFMS_SOURCE_HAALIOGG);
-	}
-#endif
-
-	return new FFLAVFIndexer(Filename, FormatContext);
-}
-
-FFMS_Indexer::FFMS_Indexer(const char *Filename) : DecodingBuffer(AVCODEC_MAX_AUDIO_FRAME_SIZE * 10) {
-	IndexMask = 0;
-	DumpMask = 0;
-	ErrorHandling = FFMS_IEH_CLEAR_TRACK;
-	IC = NULL;
-	ICPrivate = NULL;
-	ANC = NULL;
-	ANCPrivate = NULL;
-
-	FFMS_Index::CalculateFileSignature(Filename, &Filesize, Digest);
-}
-
-FFMS_Indexer::~FFMS_Indexer() {
-
-}
-
-void FFMS_Indexer::WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track, int DBSize) {
-	// Delay writer creation until after an audio frame has been decoded. This ensures that all parameters are known when writing the headers.
-	if (DBSize <= 0) return;
-
-	if (!AudioContext.W64Writer) {
-		FFMS_AudioProperties AP;
-		FillAP(AP, AudioContext.CodecContext, (*Index)[Track]);
-		int FNSize = (*ANC)(SourceFile, Track, &AP, NULL, 0, ANCPrivate);
-		if (FNSize <= 0) {
-			DumpMask = DumpMask & ~(1 << Track);
-			return;
-		}
-
-		std::vector<char> WName(FNSize);
-		(*ANC)(SourceFile, Track, &AP, &WName[0], FNSize, ANCPrivate);
-		std::string WN(&WName[0]);
-		try {
-			AudioContext.W64Writer =
-				new Wave64Writer(WN.c_str(),
-					av_get_bits_per_sample_fmt(AudioContext.CodecContext->sample_fmt),
-					AudioContext.CodecContext->channels,
-					AudioContext.CodecContext->sample_rate,
-					(AudioContext.CodecContext->sample_fmt == AV_SAMPLE_FMT_FLT) || (AudioContext.CodecContext->sample_fmt == AV_SAMPLE_FMT_DBL));
-		} catch (...) {
-			throw FFMS_Exception(FFMS_ERROR_WAVE_WRITER, FFMS_ERROR_FILE_WRITE,
-				"Failed to write wave data");
-		}
-	}
-
-	AudioContext.W64Writer->WriteData(&DecodingBuffer[0], DBSize);
-}
-
-int64_t FFMS_Indexer::IndexAudioPacket(int Track, AVPacket *Packet, SharedAudioContext &Context, FFMS_Index &TrackIndices) {
-	AVCodecContext *CodecContext = Context.CodecContext;
-	int64_t StartSample = Context.CurrentSample;
-	int Read = 0;
-	while (Packet->size > 0) {
-		int dbsize = AVCODEC_MAX_AUDIO_FRAME_SIZE*10;
-		int Ret = avcodec_decode_audio3(CodecContext, (int16_t *)&DecodingBuffer[0], &dbsize, Packet);
-		if (Ret < 0) {
-			if (ErrorHandling == FFMS_IEH_ABORT) {
-				throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING, "Audio decoding error");
-			} else if (ErrorHandling == FFMS_IEH_CLEAR_TRACK) {
-				TrackIndices[Track].clear();
-				IndexMask &= ~(1 << Track);
-			} else if (ErrorHandling == FFMS_IEH_STOP_TRACK) {
-				IndexMask &= ~(1 << Track);
-			}
-			break;
-		}
-		Packet->size -= Ret;
-		Packet->data += Ret;
-		Read += Ret;
-
-		CheckAudioProperties(Track, CodecContext);
-
-		if (dbsize > 0)
-			Context.CurrentSample += (dbsize * 8) / (av_get_bits_per_sample_fmt(CodecContext->sample_fmt) * CodecContext->channels);
-
-		if (DumpMask & (1 << Track))
-			WriteAudio(Context, &TrackIndices, Track, dbsize);
-	}
-	Packet->size += Read;
-	Packet->data -= Read;
-	return Context.CurrentSample - StartSample;
-}
-
-void FFMS_Indexer::CheckAudioProperties(int Track, AVCodecContext *Context) {
-	std::map<int, FFMS_AudioProperties>::iterator it = LastAudioProperties.find(Track);
-	if (it == LastAudioProperties.end()) {
-		FFMS_AudioProperties &AP = LastAudioProperties[Track];
-		AP.SampleRate = Context->sample_rate;
-		AP.SampleFormat = Context->sample_fmt;
-		AP.Channels = Context->channels;
-	}
-	else if (it->second.SampleRate   != Context->sample_rate ||
-			 it->second.SampleFormat != Context->sample_fmt ||
-			 it->second.Channels     != Context->channels) {
-		std::ostringstream buf;
-		buf <<
-			"Audio format change detected. This is currently unsupported."
-			<< " Channels: " << it->second.Channels << " -> " << Context->channels << ";"
-			<< " Sample rate: " << it->second.SampleRate << " -> " << Context->sample_rate << ";"
-			<< " Sample format: " << GetLAVCSampleFormatName((AVSampleFormat)it->second.SampleFormat) << " -> "
-			<< GetLAVCSampleFormatName(Context->sample_fmt);
-		throw FFMS_Exception(FFMS_ERROR_UNSUPPORTED, FFMS_ERROR_DECODING, buf.str());
-	}
-}
diff --git a/aegisub/libffms/src/core/indexing.h b/aegisub/libffms/src/core/indexing.h
deleted file mode 100644
index 9758b62b7..000000000
--- a/aegisub/libffms/src/core/indexing.h
+++ /dev/null
@@ -1,195 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#ifndef INDEXING_H
-#define INDEXING_H
-
-#include <map>
-#include <memory>
-#include "utils.h"
-#include "wave64writer.h"
-
-#ifdef HAALISOURCE
-#	define WIN32_LEAN_AND_MEAN
-#	define _WIN32_DCOM
-#	include <windows.h>
-#	include <tchar.h>
-#	include <atlbase.h>
-#	include <dshow.h>
-#	include <initguid.h>
-#	include "CoParser.h"
-#	include "guids.h"
-#endif
-
-
-class SharedVideoContext {
-private:
-	bool FreeCodecContext;
-public:
-	AVCodecContext *CodecContext;
-	AVCodecParserContext *Parser;
-	TrackCompressionContext *TCC;
-
-	SharedVideoContext(bool FreeCodecContext);
-	~SharedVideoContext();
-};
-
-class SharedAudioContext {
-private:
-	bool FreeCodecContext;
-public:
-	AVCodecContext *CodecContext;
-	Wave64Writer *W64Writer;
-	int64_t CurrentSample;
-	TrackCompressionContext *TCC;
-
-	SharedAudioContext(bool FreeCodecContext);
-	~SharedAudioContext();
-};
-
-struct TFrameInfo {
-public:
-	FFMS_FRAMEINFO_COMMON
-	int64_t SampleStart;
-	unsigned int SampleCount;
-	int64_t FilePos;
-	unsigned int FrameSize;
-	size_t OriginalPos;
-
-	TFrameInfo();
-	static TFrameInfo VideoFrameInfo(int64_t PTS, int RepeatPict, bool KeyFrame, int64_t FilePos = 0, unsigned int FrameSize = 0);
-	static TFrameInfo AudioFrameInfo(int64_t PTS, int64_t SampleStart, int64_t SampleCount, bool KeyFrame, int64_t FilePos = 0, unsigned int FrameSize = 0);
-private:
-	TFrameInfo(int64_t PTS, int64_t SampleStart, unsigned int SampleCount, int RepeatPict, bool KeyFrame, int64_t FilePos, unsigned int FrameSize);
-};
-
-class FFMS_Track : public std::vector<TFrameInfo> {
-public:
-	FFMS_TrackType TT;
-	FFMS_TrackTimeBase TB;
-	bool UseDTS;
-
-	int FindClosestVideoKeyFrame(int Frame);
-	int FrameFromPTS(int64_t PTS);
-	int ClosestFrameFromPTS(int64_t PTS);
-	void WriteTimecodes(const char *TimecodeFile);
-
-	FFMS_Track();
-	FFMS_Track(int64_t Num, int64_t Den, FFMS_TrackType TT, bool UseDTS = false);
-};
-
-class FFMS_Index : public std::vector<FFMS_Track> {
-public:
-	static void CalculateFileSignature(const char *Filename, int64_t *Filesize, uint8_t Digest[20]);
-
-	int Decoder;
-	int64_t Filesize;
-	uint8_t Digest[20];
-
-	void Sort();
-	bool CompareFileSignature(const char *Filename);
-	void WriteIndex(const char *IndexFile);
-	void ReadIndex(const char *IndexFile);
-
-	FFMS_Index();
-	FFMS_Index(int64_t Filesize, uint8_t Digest[20]);
-};
-
-class FFMS_Indexer {
-	std::map<int, FFMS_AudioProperties> LastAudioProperties;
-protected:
-	int IndexMask;
-	int DumpMask;
-	int ErrorHandling;
-	TIndexCallback IC;
-	void *ICPrivate;
-	TAudioNameCallback ANC;
-	void *ANCPrivate;
-	const char *SourceFile;
-	AlignedBuffer<uint8_t> DecodingBuffer;
-
-	int64_t Filesize;
-	uint8_t Digest[20];
-
-	void WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track, int DBSize);
-	void CheckAudioProperties(int Track, AVCodecContext *Context);
-	int64_t IndexAudioPacket(int Track, AVPacket *Packet, SharedAudioContext &Context, FFMS_Index &TrackIndices);
-public:
-	static FFMS_Indexer *CreateIndexer(const char *Filename);
-	FFMS_Indexer(const char *Filename);
-	virtual ~FFMS_Indexer();
-	void SetIndexMask(int IndexMask);
-	void SetDumpMask(int DumpMask);
-	void SetErrorHandling(int ErrorHandling);
-	void SetProgressCallback(TIndexCallback IC, void *ICPrivate);
-	void SetAudioNameCallback(TAudioNameCallback ANC, void *ANCPrivate);
-	virtual FFMS_Index *DoIndexing() = 0;
-	virtual int GetNumberOfTracks() = 0;
-	virtual FFMS_TrackType GetTrackType(int Track) = 0;
-	virtual const char *GetTrackCodec(int Track) = 0;
-};
-
-class FFLAVFIndexer : public FFMS_Indexer {
-	AVFormatContext *FormatContext;
-	void ReadTS(const AVPacket &Packet, int64_t &TS, bool &UseDTS);
-public:
-	FFLAVFIndexer(const char *Filename, AVFormatContext *FormatContext);
-	~FFLAVFIndexer();
-	FFMS_Index *DoIndexing();
-	int GetNumberOfTracks();
-	FFMS_TrackType GetTrackType(int Track);
-	const char *GetTrackCodec(int Track);
-};
-
-class FFMatroskaIndexer : public FFMS_Indexer {
-private:
-	MatroskaFile *MF;
-	MatroskaReaderContext MC;
-	AVCodec *Codec[32];
-public:
-	FFMatroskaIndexer(const char *Filename);
-	~FFMatroskaIndexer();
-	FFMS_Index *DoIndexing();
-	int GetNumberOfTracks();
-	FFMS_TrackType GetTrackType(int Track);
-	const char *GetTrackCodec(int Track);
-};
-
-#ifdef HAALISOURCE
-
-class FFHaaliIndexer : public FFMS_Indexer {
-private:
-	int SourceMode;
-	CComPtr<IMMContainer> pMMC;
-	int NumTracks;
-	FFMS_TrackType TrackType[32];
-	CComQIPtr<IPropertyBag> PropertyBags[32];
-	int64_t Duration;
-public:
-	FFHaaliIndexer(const char *Filename, enum FFMS_Sources SourceMode);
-	FFMS_Index *DoIndexing();
-	int GetNumberOfTracks();
-	FFMS_TrackType GetTrackType(int Track);
-	const char *GetTrackCodec(int Track);
-};
-
-#endif // HAALISOURCE
-
-#endif
diff --git a/aegisub/libffms/src/core/lavfaudio.cpp b/aegisub/libffms/src/core/lavfaudio.cpp
deleted file mode 100644
index ac1fde6d0..000000000
--- a/aegisub/libffms/src/core/lavfaudio.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-//  Copyright (c) 2011 Thomas Goyne <tgoyne@gmail.com>
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include "audiosource.h"
-#include <cassert>
-
-FFLAVFAudio::FFLAVFAudio(const char *SourceFile, int Track, FFMS_Index &Index, int DelayMode)
-: FFMS_AudioSource(SourceFile, Index, Track)
-, FormatContext(NULL)
-{
-	LAVFOpenFile(SourceFile, FormatContext);
-
-	CodecContext.reset(FormatContext->streams[TrackNumber]->codec);
-	assert(CodecContext);
-
-	AVCodec *Codec = avcodec_find_decoder(CodecContext->codec_id);
-	try {
-		if (!Codec)
-			throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
-				"Audio codec not found");
-
-		if (avcodec_open(CodecContext, Codec) < 0)
-			throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
-				"Could not open audio codec");
-	}
-	catch (...) {
-		av_close_input_file(FormatContext);
-		throw;
-	}
-
-	if (Frames.back().PTS == Frames.front().PTS)
-		SeekOffset = -1;
-	else
-		SeekOffset = 10;
-	Init(Index, DelayMode);
-}
-
-FFLAVFAudio::~FFLAVFAudio() {
-	av_close_input_file(FormatContext);
-}
-
-void FFLAVFAudio::Seek() {
-	size_t TargetPacket = GetSeekablePacketNumber(Frames, PacketNumber);
-
-	if (av_seek_frame(FormatContext, TrackNumber, Frames[TargetPacket].PTS, AVSEEK_FLAG_BACKWARD) < 0)
-		av_seek_frame(FormatContext, TrackNumber, Frames[TargetPacket].PTS, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY);
-
-	if (TargetPacket != PacketNumber) {
-		// Decode until the PTS changes so we know where we are
-		int64_t LastPTS = Frames[PacketNumber].PTS;
-		while (LastPTS == Frames[PacketNumber].PTS) DecodeNextBlock();
-	}
-}
-
-bool FFLAVFAudio::ReadPacket(AVPacket *Packet) {
-	InitNullPacket(*Packet);
-
-	while (av_read_frame(FormatContext, Packet) >= 0) {
-		if (Packet->stream_index == TrackNumber) {
-			while (Frames[PacketNumber].PTS < Packet->pts) ++PacketNumber;
-			return true;
-		}
-		av_free_packet(Packet);
-	}
-	return false;
-}
-void FFLAVFAudio::FreePacket(AVPacket *Packet) {
-	av_free_packet(Packet);
-}
diff --git a/aegisub/libffms/src/core/lavfindexer.cpp b/aegisub/libffms/src/core/lavfindexer.cpp
deleted file mode 100644
index c48dfb682..000000000
--- a/aegisub/libffms/src/core/lavfindexer.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include "indexing.h"
-
-
-
-FFLAVFIndexer::FFLAVFIndexer(const char *Filename, AVFormatContext *FormatContext) : FFMS_Indexer(Filename) {
-	SourceFile = Filename;
-	this->FormatContext = FormatContext;
-	
-	if (av_find_stream_info(FormatContext) < 0) {
-		av_close_input_file(FormatContext);
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			"Couldn't find stream information");
-	}
-}
-
-FFLAVFIndexer::~FFLAVFIndexer() {
-	av_close_input_file(FormatContext);
-}
-
-FFMS_Index *FFLAVFIndexer::DoIndexing() {
-	std::vector<SharedAudioContext> AudioContexts(FormatContext->nb_streams, SharedAudioContext(false));
-	std::vector<SharedVideoContext> VideoContexts(FormatContext->nb_streams, SharedVideoContext(false));
-
-	std::auto_ptr<FFMS_Index> TrackIndices(new FFMS_Index(Filesize, Digest));
-	TrackIndices->Decoder = FFMS_SOURCE_LAVF;
-
-	for (unsigned int i = 0; i < FormatContext->nb_streams; i++) {
-		TrackIndices->push_back(FFMS_Track((int64_t)FormatContext->streams[i]->time_base.num * 1000,
-			FormatContext->streams[i]->time_base.den,
-			static_cast<FFMS_TrackType>(FormatContext->streams[i]->codec->codec_type)));
-
-		if (FormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
-			AVCodec *VideoCodec = avcodec_find_decoder(FormatContext->streams[i]->codec->codec_id);
-			if (!VideoCodec)
-				throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_UNSUPPORTED,
-					"Video codec not found");
-
-			if (avcodec_open(FormatContext->streams[i]->codec, VideoCodec) < 0)
-				throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
-					"Could not open video codec");
-
-			VideoContexts[i].CodecContext = FormatContext->streams[i]->codec;
-			VideoContexts[i].Parser = av_parser_init(FormatContext->streams[i]->codec->codec_id);
-			if (VideoContexts[i].Parser)
-				VideoContexts[i].Parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
-			IndexMask |= 1 << i;
-		}
-		else if (IndexMask & (1 << i) && FormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
-			AVCodecContext *AudioCodecContext = FormatContext->streams[i]->codec;
-
-			AVCodec *AudioCodec = avcodec_find_decoder(AudioCodecContext->codec_id);
-			if (AudioCodec == NULL)
-				throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_UNSUPPORTED,
-					"Audio codec not found");
-
-			if (avcodec_open(AudioCodecContext, AudioCodec) < 0)
-				throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
-					"Could not open audio codec");
-
-			AudioContexts[i].CodecContext = AudioCodecContext;
-		} else {
-			IndexMask &= ~(1 << i);
-		}
-	}
-
-	AVPacket Packet;
-	InitNullPacket(Packet);
-	std::vector<int64_t> LastValidTS;
-	LastValidTS.resize(FormatContext->nb_streams, ffms_av_nopts_value);
-
-	while (av_read_frame(FormatContext, &Packet) >= 0) {
-		// Update progress
-		// FormatContext->pb can apparently be NULL when opening images.
-		if (IC && FormatContext->pb) {
-			if ((*IC)(FormatContext->pb->pos, FormatContext->file_size, ICPrivate))	
-				throw FFMS_Exception(FFMS_ERROR_CANCELLED, FFMS_ERROR_USER,
-					"Cancelled by user");
-		}
-		if (!(IndexMask & (1 << Packet.stream_index))) {
-			av_free_packet(&Packet);
-			continue;
-		}
-
-		int Track = Packet.stream_index;
-		bool KeyFrame = !!(Packet.flags & AV_PKT_FLAG_KEY);
-		ReadTS(Packet, LastValidTS[Track], (*TrackIndices)[Track].UseDTS);
-
-		if (FormatContext->streams[Track]->codec->codec_type == CODEC_TYPE_VIDEO) {
-			if (LastValidTS[Track] == ffms_av_nopts_value)
-				throw FFMS_Exception(FFMS_ERROR_INDEXING, FFMS_ERROR_PARSER,
-				"Invalid initial pts and dts");
-
-			int RepeatPict = -1;
-
-			if (VideoContexts[Track].Parser) {
-				uint8_t *OB;
-				int OBSize;
-				av_parser_parse2(VideoContexts[Track].Parser, VideoContexts[Track].CodecContext, &OB, &OBSize, Packet.data, Packet.size, Packet.pts, Packet.dts, Packet.pos);
-				RepeatPict = VideoContexts[Track].Parser->repeat_pict;
-			}
-
-			(*TrackIndices)[Track].push_back(TFrameInfo::VideoFrameInfo(LastValidTS[Track], RepeatPict, KeyFrame, Packet.pos));
-		}
-		else if (FormatContext->streams[Track]->codec->codec_type == CODEC_TYPE_AUDIO) {
-			int64_t StartSample = AudioContexts[Track].CurrentSample;
-			int64_t SampleCount = IndexAudioPacket(Track, &Packet, AudioContexts[Track], *TrackIndices);
-
-			if (SampleCount != 0)
-				(*TrackIndices)[Track].push_back(TFrameInfo::AudioFrameInfo(LastValidTS[Track],
-					StartSample, SampleCount, KeyFrame, Packet.pos));
-		}
-
-		av_free_packet(&Packet);
-	}
-
-	TrackIndices->Sort();
-	return TrackIndices.release();
-}
-
-void FFLAVFIndexer::ReadTS(const AVPacket &Packet, int64_t &TS, bool &UseDTS) {
-	if (!UseDTS && Packet.pts != ffms_av_nopts_value)
-		TS = Packet.pts;
-	if (TS == ffms_av_nopts_value)
-		UseDTS = true;
-	if (UseDTS && Packet.dts != ffms_av_nopts_value)
-		TS = Packet.dts;
-}
-
-int FFLAVFIndexer::GetNumberOfTracks() {
-	return FormatContext->nb_streams;
-}
-
-FFMS_TrackType FFLAVFIndexer::GetTrackType(int Track) {
-	return static_cast<FFMS_TrackType>(FormatContext->streams[Track]->codec->codec_type);
-}
-
-const char *FFLAVFIndexer::GetTrackCodec(int Track) {
-	AVCodec *codec = avcodec_find_decoder(FormatContext->streams[Track]->codec->codec_id);
-	return codec ? codec->name : NULL;
-}
diff --git a/aegisub/libffms/src/core/lavfvideo.cpp b/aegisub/libffms/src/core/lavfvideo.cpp
deleted file mode 100644
index cb2b9bdb2..000000000
--- a/aegisub/libffms/src/core/lavfvideo.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include "videosource.h"
-
-
-
-void FFLAVFVideo::Free(bool CloseCodec) {
-	if (CloseCodec)
-		avcodec_close(CodecContext);
-	av_close_input_file(FormatContext);
-}
-
-FFLAVFVideo::FFLAVFVideo(const char *SourceFile, int Track, FFMS_Index *Index,
-	int Threads, int SeekMode)
-	: Res(FFSourceResources<FFMS_VideoSource>(this)), FFMS_VideoSource(SourceFile, Index, Track) {
-
-	FormatContext = NULL;
-	AVCodec *Codec = NULL;
-	this->SeekMode = SeekMode;
-	VideoTrack = Track;
-	Frames = (*Index)[VideoTrack];
-
-	LAVFOpenFile(SourceFile, FormatContext);
-
-	if (SeekMode >= 0 && av_seek_frame(FormatContext, VideoTrack, Frames[0].PTS, AVSEEK_FLAG_BACKWARD) < 0)
-		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
-			"Video track is unseekable");
-
-	CodecContext = FormatContext->streams[VideoTrack]->codec;
-	if (avcodec_thread_init(CodecContext, Threads))
-		CodecContext->thread_count = 1;
-
-	Codec = avcodec_find_decoder(CodecContext->codec_id);
-	if (Codec == NULL)
-		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
-			"Video codec not found");
-
-	if (avcodec_open(CodecContext, Codec) < 0)
-		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
-			"Could not open video codec");
-
-	Res.CloseCodec(true);
-
-	// Always try to decode a frame to make sure all required parameters are known
-	int64_t Dummy;
-	DecodeNextFrame(&Dummy);
-
-	//VP.image_type = VideoInfo::IT_TFF;
-	VP.FPSDenominator = FormatContext->streams[VideoTrack]->time_base.num;
-	VP.FPSNumerator = FormatContext->streams[VideoTrack]->time_base.den;
-	VP.RFFDenominator = CodecContext->time_base.num;
-	VP.RFFNumerator = CodecContext->time_base.den;
-	if (CodecContext->codec_id == CODEC_ID_H264) {
-		if (VP.RFFNumerator & 1)
-			VP.RFFDenominator *= 2;
-		else
-			VP.RFFNumerator /= 2;
-	}
-	VP.NumFrames = Frames.size();
-	VP.TopFieldFirst = DecodeFrame->top_field_first;
-#ifdef FFMS_HAVE_FFMPEG_COLORSPACE_INFO
-	VP.ColorSpace = CodecContext->colorspace;
-	VP.ColorRange = CodecContext->color_range;
-#else
-	VP.ColorSpace = 0;
-	VP.ColorRange = 0;
-#endif
-	// these pixfmt's are deprecated but still used
-	if (
-		CodecContext->pix_fmt == PIX_FMT_YUVJ420P 
-		|| CodecContext->pix_fmt == PIX_FMT_YUVJ422P
-		|| CodecContext->pix_fmt == PIX_FMT_YUVJ444P
-	)
-		VP.ColorRange = AVCOL_RANGE_JPEG;
-
-
-	VP.FirstTime = ((Frames.front().PTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
-	VP.LastTime = ((Frames.back().PTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
-
-	if (CodecContext->width <= 0 || CodecContext->height <= 0)
-		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
-			"Codec returned zero size video");
-
-	// sanity check framerate
-	if (VP.FPSDenominator > VP.FPSNumerator || VP.FPSDenominator <= 0 || VP.FPSNumerator <= 0) {
-		VP.FPSDenominator = 1;
-		VP.FPSNumerator = 30;
-	}
-
-	// Calculate the average framerate
-	if (Frames.size() >= 2) {
-		double PTSDiff = (double)(Frames.back().PTS - Frames.front().PTS);
-		double TD = (double)(Frames.TB.Den);
-		double TN = (double)(Frames.TB.Num);
-		VP.FPSDenominator = (unsigned int)(((double)1000000) / (double)((VP.NumFrames - 1) / ((PTSDiff * TN/TD) / (double)1000)));
-		VP.FPSNumerator = 1000000; 
-	}
-
-	// attempt to correct framerate to the proper NTSC fraction, if applicable
-	CorrectNTSCRationalFramerate(&VP.FPSNumerator, &VP.FPSDenominator);
-	// correct the timebase, if necessary
-	CorrectTimebase(&VP, &Frames.TB);
-
-	// Cannot "output" to PPFrame without doing all other initialization
-	// This is the additional mess required for seekmode=-1 to work in a reasonable way
-	OutputFrame(DecodeFrame);
-
-	// Set AR variables
-	VP.SARNum = CodecContext->sample_aspect_ratio.num;
-	VP.SARDen = CodecContext->sample_aspect_ratio.den;
-}
-
-void FFLAVFVideo::DecodeNextFrame(int64_t *AStartTime) {
-	AVPacket Packet;
-	InitNullPacket(Packet);
-	int FrameFinished = 0;
-	*AStartTime = -1;
-
-	if (InitialDecode == -1) {
-		if (DelayCounter > CodecContext->has_b_frames) {
-			DelayCounter--;
-			goto Done;
-		} else {
-			InitialDecode = 0;
-		}
-	}
-
-	while (av_read_frame(FormatContext, &Packet) >= 0) {
-        if (Packet.stream_index == VideoTrack) {
-			if (*AStartTime < 0) {
-				if (Frames.UseDTS)
-					*AStartTime = Packet.dts;
-				else
-					*AStartTime = Packet.pts;
-			}
-
-			avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &Packet);
-
-			if (!FrameFinished)
-				DelayCounter++;
-			if (DelayCounter > CodecContext->has_b_frames && !InitialDecode) {
-				av_free_packet(&Packet);
-				goto Done;
-			}
-        }
-
-        av_free_packet(&Packet);
-
-		if (FrameFinished)
-			goto Done;
-	}
-
-	// Flush the last frames
-	if (CodecContext->has_b_frames) {
-		AVPacket NullPacket;
-		InitNullPacket(NullPacket);
-		avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &NullPacket);
-	}
-
-	if (!FrameFinished)
-		goto Error;
-
-Error:
-Done:
-	if (InitialDecode == 1) InitialDecode = -1;
-}
-
-FFMS_Frame *FFLAVFVideo::GetFrame(int n) {
-	GetFrameCheck(n);
-
-	if (LastFrameNum == n)
-		return &LocalFrame;
-
-	bool HasSeeked = false;
-	int SeekOffset = 0;
-
-	int ClosestKF = 0;
-	if (SeekMode >= 0) {
-		ClosestKF = Frames.FindClosestVideoKeyFrame(n);
-
-		if (SeekMode == 0) {
-			if (n < CurrentFrame) {
-				av_seek_frame(FormatContext, VideoTrack, Frames[0].PTS, AVSEEK_FLAG_BACKWARD);
-				avcodec_flush_buffers(CodecContext);
-				CurrentFrame = 0;
-				DelayCounter = 0;
-				InitialDecode = 1;
-			}
-		} else {
-			// 10 frames is used as a margin to prevent excessive seeking since the predicted best keyframe isn't always selected by avformat
-			if (n < CurrentFrame || ClosestKF > CurrentFrame + 10 || (SeekMode == 3 && n > CurrentFrame + 10)) {
-ReSeek:
-				av_seek_frame(FormatContext, VideoTrack,
-					(SeekMode == 3) ? Frames[n].PTS : Frames[ClosestKF + SeekOffset].PTS,
-					AVSEEK_FLAG_BACKWARD);
-				avcodec_flush_buffers(CodecContext);
-				HasSeeked = true;
-				DelayCounter = 0;
-				InitialDecode = 1;
-			}
-		}
-	} else if (n < CurrentFrame) {
-		throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_INVALID_ARGUMENT,
-			"Non-linear access attempted");
-	}
-
-	do {
-		int64_t StartTime;
-		if (CurrentFrame+CodecContext->has_b_frames >= n)
-			CodecContext->skip_frame = AVDISCARD_DEFAULT;
-		else
-			CodecContext->skip_frame = AVDISCARD_NONREF;
-		DecodeNextFrame(&StartTime);
-
-		if (HasSeeked) {
-			HasSeeked = false;
-
-			// Is the seek destination time known? Does it belong to a frame?
-			if (StartTime < 0 || (CurrentFrame = Frames.FrameFromPTS(StartTime)) < 0) {
-				switch (SeekMode) {
-					case 1:
-						// No idea where we are so go back a bit further
-						if (ClosestKF + SeekOffset == 0)
-							throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
-								"Frame accurate seeking is not possible in this file");
-
-
-						SeekOffset -= FFMIN(10, ClosestKF + SeekOffset);
-						goto ReSeek;
-					case 2:
-					case 3:
-						CurrentFrame = Frames.ClosestFrameFromPTS(StartTime);
-						break;
-					default:
-						throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_UNKNOWN,
-							"Failed assertion");
-				}	
-			}
-		}
-
-		CurrentFrame++;
-	} while (CurrentFrame <= n);
-
-	LastFrameNum = n;
-	return OutputFrame(DecodeFrame);
-}
diff --git a/aegisub/libffms/src/core/matroskaaudio.cpp b/aegisub/libffms/src/core/matroskaaudio.cpp
deleted file mode 100644
index 95d45cdc5..000000000
--- a/aegisub/libffms/src/core/matroskaaudio.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//  Copyright (c) 2011 Thomas Goyne <tgoyne@gmail.com>
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include "audiosource.h"
-#include <cassert>
-
-FFMatroskaAudio::FFMatroskaAudio(const char *SourceFile, int Track, FFMS_Index &Index, int DelayMode)
-: FFMS_AudioSource(SourceFile, Index, Track)
-, TI(NULL)
-{
-	if (!(MC.ST.fp = ffms_fopen(SourceFile, "rb")))
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			std::string("Can't open '") + SourceFile + "': " + strerror(errno));
-
-	setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE);
-
-	if (!(MF = mkv_OpenEx(&MC.ST.base, 0, 0, ErrorMessage, sizeof(ErrorMessage))))
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			std::string("Can't parse Matroska file: ") + ErrorMessage);
-
-	TI = mkv_GetTrackInfo(MF, Track);
-	assert(TI);
-
-	if (TI->CompEnabled)
-		TCC.reset(new TrackCompressionContext(MF, TI, Track));
-
-	CodecContext.reset(avcodec_alloc_context(), DeleteMatroskaCodecContext);
-	assert(CodecContext);
-
-	AVCodec *Codec = avcodec_find_decoder(MatroskaToFFCodecID(TI->CodecID, TI->CodecPrivate, 0, TI->AV.Audio.BitDepth));
-	if (!Codec) {
-		mkv_Close(MF);
-		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Audio codec not found");
-	}
-
-	InitializeCodecContextFromMatroskaTrackInfo(TI, CodecContext);
-
-	if (avcodec_open(CodecContext, Codec) < 0) {
-		mkv_Close(MF);
-		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Could not open audio codec");
-	}
-
-	Init(Index, DelayMode);
-}
-
-FFMatroskaAudio::~FFMatroskaAudio() {
-	mkv_Close(MF);
-}
-
-bool FFMatroskaAudio::ReadPacket(AVPacket *Packet) {
-	ReadFrame(CurrentFrame->FilePos, CurrentFrame->FrameSize, TCC.get(), MC);
-	InitNullPacket(*Packet);
-	Packet->data = MC.Buffer;
-	Packet->size = CurrentFrame->FrameSize + ((TCC.get() && TCC->CompressionMethod == COMP_PREPEND) ? TCC->CompressedPrivateDataSize : 0);
-	Packet->flags = CurrentFrame->KeyFrame ? AV_PKT_FLAG_KEY : 0;
-
-	return true;
-}
diff --git a/aegisub/libffms/src/core/matroskaindexer.cpp b/aegisub/libffms/src/core/matroskaindexer.cpp
deleted file mode 100644
index d9dfdde94..000000000
--- a/aegisub/libffms/src/core/matroskaindexer.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include "indexing.h"
-#include "matroskaparser.h"
-
-
-
-FFMatroskaIndexer::FFMatroskaIndexer(const char *Filename) : FFMS_Indexer(Filename) {
-	SourceFile = Filename;
-	char ErrorMessage[256];
-	for (int i = 0; i < 32; i++) {
-		Codec[i] = NULL;
-	}
-
-	InitStdIoStream(&MC.ST);
-	MC.ST.fp = ffms_fopen(SourceFile, "rb");
-	if (MC.ST.fp == NULL) {
-		std::ostringstream buf;
-		buf << "Can't open '" << SourceFile << "': " << strerror(errno);
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, buf.str());
-	}
-
-	setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE);
-
-	MF = mkv_OpenEx(&MC.ST.base, 0, 0, ErrorMessage, sizeof(ErrorMessage));
-	if (MF == NULL) {
-		std::ostringstream buf;
-		buf << "Can't parse Matroska file: " << ErrorMessage;
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, buf.str());
-	}
-
-	for (unsigned int i = 0; i < mkv_GetNumTracks(MF); i++) {
-		TrackInfo *TI = mkv_GetTrackInfo(MF, i);
-		Codec[i] = avcodec_find_decoder(MatroskaToFFCodecID(TI->CodecID, TI->CodecPrivate, 0, TI->AV.Audio.BitDepth));
-	}
-}
-
-FFMatroskaIndexer::~FFMatroskaIndexer() {
-	mkv_Close(MF);
-}
-
-FFMS_Index *FFMatroskaIndexer::DoIndexing() {
-	std::vector<SharedAudioContext> AudioContexts(mkv_GetNumTracks(MF), SharedAudioContext(true));
-	std::vector<SharedVideoContext> VideoContexts(mkv_GetNumTracks(MF), SharedVideoContext(true));
-
-	std::auto_ptr<FFMS_Index> TrackIndices(new FFMS_Index(Filesize, Digest));
-	TrackIndices->Decoder = FFMS_SOURCE_MATROSKA;
-
-	for (unsigned int i = 0; i < mkv_GetNumTracks(MF); i++) {
-		TrackInfo *TI = mkv_GetTrackInfo(MF, i);
-		TrackIndices->push_back(FFMS_Track(mkv_TruncFloat(mkv_GetTrackInfo(MF, i)->TimecodeScale), 1000000, HaaliTrackTypeToFFTrackType(mkv_GetTrackInfo(MF, i)->Type)));
-
-		if (!Codec[i]) continue;
-
-		AVCodecContext *CodecContext = avcodec_alloc_context();
-		InitializeCodecContextFromMatroskaTrackInfo(TI, CodecContext);
-
-		try {
-			if (TI->Type == TT_VIDEO && (VideoContexts[i].Parser = av_parser_init(Codec[i]->id))) {
-				if (avcodec_open(CodecContext, Codec[i]) < 0)
-					throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
-						"Could not open video codec");
-
-				if (TI->CompEnabled)
-					VideoContexts[i].TCC = new TrackCompressionContext(MF, TI, i);
-
-				VideoContexts[i].CodecContext = CodecContext;
-				VideoContexts[i].Parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
-			}
-			else if (IndexMask & (1 << i) && TI->Type == TT_AUDIO) {
-				if (avcodec_open(CodecContext, Codec[i]) < 0)
-					throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
-						"Could not open audio codec");
-
-				if (TI->CompEnabled)
-					AudioContexts[i].TCC = new TrackCompressionContext(MF, TI, i);
-
-				AudioContexts[i].CodecContext = CodecContext;
-			} else {
-				IndexMask &= ~(1 << i);
-				av_freep(&CodecContext);
-			}
-		}
-		catch (...) {
-			av_freep(&CodecContext);
-			throw;
-		}
-	}
-
-	ulonglong StartTime, EndTime, FilePos;
-	unsigned int Track, FrameFlags, FrameSize;
-	AVPacket TempPacket;
-	InitNullPacket(TempPacket);
-
-	while (mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0) {
-		// Update progress
-		if (IC && (*IC)(ftello(MC.ST.fp), Filesize, ICPrivate))
-			throw FFMS_Exception(FFMS_ERROR_CANCELLED, FFMS_ERROR_USER, "Cancelled by user");
-
-		if (mkv_GetTrackInfo(MF, Track)->Type == TT_VIDEO) {
-			uint8_t *OB;
-			int OBSize;
-			int RepeatPict = -1;
-
-			if (VideoContexts[Track].Parser) {
-				av_parser_parse2(VideoContexts[Track].Parser, VideoContexts[Track].CodecContext, &OB, &OBSize, TempPacket.data, TempPacket.size, ffms_av_nopts_value, ffms_av_nopts_value, ffms_av_nopts_value);
-				RepeatPict = VideoContexts[Track].Parser->repeat_pict;
-			}
-
-			(*TrackIndices)[Track].push_back(TFrameInfo::VideoFrameInfo(StartTime, RepeatPict, (FrameFlags & FRAME_KF) != 0, FilePos, FrameSize));
-		} else if (mkv_GetTrackInfo(MF, Track)->Type == TT_AUDIO && (IndexMask & (1 << Track))) {
-			TrackCompressionContext *TCC = AudioContexts[Track].TCC;
-			unsigned int CompressedFrameSize = FrameSize;
-			ReadFrame(FilePos, FrameSize, TCC, MC);
-			TempPacket.data = MC.Buffer;
-			TempPacket.size = (TCC && TCC->CompressionMethod == COMP_PREPEND) ? FrameSize + TCC->CompressedPrivateDataSize : FrameSize;
-			TempPacket.flags = FrameFlags & FRAME_KF ? AV_PKT_FLAG_KEY : 0;
-
-			int64_t StartSample = AudioContexts[Track].CurrentSample;
-			int64_t SampleCount = IndexAudioPacket(Track, &TempPacket, AudioContexts[Track], *TrackIndices);
-
-			if (SampleCount != 0)
-				(*TrackIndices)[Track].push_back(TFrameInfo::AudioFrameInfo(StartTime, StartSample,
-					SampleCount, (FrameFlags & FRAME_KF) != 0, FilePos, CompressedFrameSize));
-		}
-	}
-
-	TrackIndices->Sort();
-	return TrackIndices.release();
-}
-
-int FFMatroskaIndexer::GetNumberOfTracks() {
-	return mkv_GetNumTracks(MF);
-}
-
-FFMS_TrackType FFMatroskaIndexer::GetTrackType(int Track) {
-	return HaaliTrackTypeToFFTrackType(mkv_GetTrackInfo(MF, Track)->Type);
-}
-
-const char *FFMatroskaIndexer::GetTrackCodec(int Track) {
-	return Codec[Track] ? Codec[Track]->name : NULL;
-}
diff --git a/aegisub/libffms/src/core/matroskaparser.c b/aegisub/libffms/src/core/matroskaparser.c
deleted file mode 100644
index 627d70d08..000000000
--- a/aegisub/libffms/src/core/matroskaparser.c
+++ /dev/null
@@ -1,3371 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Mike Matsnev.  All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. 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.
- * 3. Absolutely no warranty of function or purpose is made by the author
- *    Mike Matsnev.
- *
- * 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.
- * 
- * $Id: MatroskaParser.c,v 1.73 2010/03/05 22:41:47 mike Exp $
- * 
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <setjmp.h>
-
-#ifdef _WIN32
-#ifdef _MSC_VER
-// MS names some functions differently
-#define	alloca	  _alloca
-#define	inline	  __inline
-#else /* _MSC_VER */
-// support for building with MinGW on Windows
-#include <malloc.h>
-#endif /* _MSC_VER */
-#include <tchar.h>
-#endif /* _WIN32 */
-
-#ifdef HAVE_ALLOCA_H
-#include <alloca.h>
-#endif
-
-#ifndef EVCBUG
-#define	EVCBUG
-#endif
-
-#include "matroskaparser.h"
-
-#ifdef MATROSKA_COMPRESSION_SUPPORT
-#include <zlib.h>
-#endif
-
-#define	EBML_VERSION	      1
-#define	EBML_MAX_ID_LENGTH    4
-#define	EBML_MAX_SIZE_LENGTH  8
-#define	MATROSKA_VERSION      2
-#define	MATROSKA_DOCTYPE      "matroska"
-
-#define	MAX_STRING_LEN	      1023
-#define	QSEGSIZE	      512
-#define	MAX_TRACKS	      32
-#define	MAX_READAHEAD	      (256*1024)
-
-#define	MAXCLUSTER	      (64*1048576)
-#define	MAXFRAME	      (4*1048576)
-
-#ifdef _MSC_VER
-#define	LL(x)	x##i64
-#define	ULL(x)	x##ui64
-#else
-#define	LL(x)	x##ll
-#define	ULL(x)	x##ull
-#endif
-
-#define	MAXU64		      ULL(0xffffffffffffffff)
-#define	ONE		      ULL(1)
-
-// compatibility
-static char  *mystrdup(struct InputStream *is,const char *src) {
-  size_t  len;
-  char	  *dst;
-
-  if (src==NULL)
-    return NULL;
-
-  len = strlen(src);
-  dst = is->memalloc(is,len+1);
-  if (dst==NULL)
-    return NULL;
-
-  memcpy(dst,src,len+1);
-
-  return dst;
-}
-
-static void  mystrlcpy(char *dst,const char *src,unsigned size) {
-  unsigned  i;
-
-  for (i=0;i+1<size && src[i];++i)
-    dst[i] = src[i];
-  if (i<size)
-    dst[i] = 0;
-}
-
-struct Cue {
-  ulonglong	Time;
-  ulonglong	Position;
-  ulonglong	Block;
-  unsigned char	Track;
-};
-
-struct QueueEntry {
-  struct QueueEntry *next;
-  unsigned int	    Length;
-
-  ulonglong	    Start;
-  ulonglong	    End;
-  ulonglong	    Position;
-
-  unsigned int	    flags;
-};
-
-struct Queue {
-  struct QueueEntry *head;
-  struct QueueEntry *tail;
-};
-
-#define	MPF_ERROR 0x10000
-#define	IBSZ	  1024
-
-#define	RBRESYNC  1
-
-struct MatroskaFile {
-  // parser config
-  unsigned    flags;
-
-  // input
-  InputStream *cache;
-
-  // internal buffering
-  char	      inbuf[IBSZ];
-  ulonglong   bufbase; // file offset of the first byte in buffer
-  int	      bufpos; // current read position in buffer
-  int	      buflen; // valid bytes in buffer
-
-  // error reporting
-  char	      errmsg[128];
-  jmp_buf     jb;
-
-  // pointers to key elements
-  ulonglong   pSegment;
-  ulonglong   pSeekHead;
-  ulonglong   pSegmentInfo;
-  ulonglong   pCluster;
-  ulonglong   pTracks;
-  ulonglong   pCues;
-  ulonglong   pAttachments;
-  ulonglong   pChapters;
-  ulonglong   pTags;
-
-  // flags for key elements
-  struct {
-    unsigned int  SegmentInfo:1;
-    unsigned int  Cluster:1;
-    unsigned int  Tracks:1;
-    unsigned int  Cues:1;
-    unsigned int  Attachments:1;
-    unsigned int  Chapters:1;
-    unsigned int  Tags:1;
-  } seen;
-
-  // file info
-  ulonglong   firstTimecode;
-
-  // SegmentInfo
-  struct SegmentInfo  Seg;
-
-  // Tracks
-  unsigned int	    nTracks,nTracksSize;
-  struct TrackInfo  **Tracks;
-
-  // Queues
-  struct QueueEntry *QFreeList;
-  unsigned int	    nQBlocks,nQBlocksSize;
-  struct QueueEntry **QBlocks;
-  struct Queue	    *Queues;
-  ulonglong	    readPosition;
-  unsigned int	    trackMask;
-  ulonglong	    pSegmentTop;  // offset of next byte after the segment
-  ulonglong	    tcCluster;    // current cluster timecode
-
-  // Cues
-  unsigned int	    nCues,nCuesSize;
-  struct Cue	    *Cues;
-
-  // Attachments
-  unsigned int	    nAttachments,nAttachmentsSize;
-  struct Attachment *Attachments;
-
-  // Chapters
-  unsigned int	    nChapters,nChaptersSize;
-  struct Chapter    *Chapters;
-
-  // Tags
-  unsigned int	    nTags,nTagsSize;
-  struct Tag	    *Tags;
-};
-
-///////////////////////////////////////////////////////////////////////////
-// error reporting
-static void   myvsnprintf_string(char **pdest,char *de,const char *str) {
-  char	*dest = *pdest;
-
-  while (dest < de && *str)
-    *dest++ = *str++;
-
-  *pdest = dest;
-}
-
-static void   myvsnprintf_uint_impl(char **pdest,char *de,int width,int zero,
-				    int neg,unsigned base,int letter,
-				    int ms,ulonglong val)
-{
-  char	*dest = *pdest;
-  char	tmp[21]; /* enough for 64 bit ints */
-  char	*np = tmp + sizeof(tmp);
-  int	rw,pad,trail;
-  char	pc = zero ? '0' : ' ';
-
-  *--np = '\0';
-  if (val == 0)
-    *--np = '0';
-  else
-    while (val != 0) {
-      int	  rem = (int)(val % base);
-      val = val / base;
-
-      *--np = (char)(rem < 10 ? rem + '0' : rem - 10 + letter);
-    }
-
-  rw = (int)(tmp - np + sizeof(tmp) - 1);
-  if (ms)
-    ++rw;
-
-  pad = trail = 0;
-
-  if (rw < width)
-    pad = width - rw;
-
-  if (neg)
-    trail = pad, pad = 0;
-
-  if (dest < de && ms)
-    *dest++ = '-';
-
-  while (dest < de && pad--)
-    *dest++ = pc;
-
-  while (dest < de && *np)
-    *dest++ = *np++;
-
-  while (dest < de && trail--)
-    *dest++ = ' ';
-
-  *pdest = dest;
-}
-
-static void   myvsnprintf_uint(char **pdest,char *de,int width,int zero,
-			       int neg,unsigned base,int letter,
-			       ulonglong val)
-{
-  myvsnprintf_uint_impl(pdest,de,width,zero,neg,base,letter,0,val);
-}
-
-static void   myvsnprintf_int(char **pdest,char *de,int width,int zero,
-			      int neg,unsigned base,int letter,
-			      longlong val)
-{
-  if (val < 0)
-    myvsnprintf_uint_impl(pdest,de,width,zero,neg,base,letter,1,-val);
-  else
-    myvsnprintf_uint_impl(pdest,de,width,zero,neg,base,letter,0,val);
-}
-
-static void   myvsnprintf(char *dest,unsigned dsize,const char *fmt,va_list ap) {
-  // s,d,x,u,ll
-  char	    *de = dest + dsize - 1;
-  int	    state = 0, width, zero, neg, ll;
-
-  if (dsize <= 1) {
-    if (dsize > 0)
-      *dest = '\0';
-    return;
-  }
-
-  while (*fmt && dest < de)
-    switch (state) {
-      case 0:
-	if (*fmt == '%') {
-	  ++fmt;
-	  state = 1;
-	  width = zero = neg = ll = 0;
-	} else
-	  *dest++ = *fmt++;
-	break;
-      case 1:
-	if (*fmt == '-') {
-	  neg = 1;
-	  ++fmt;
-	  state = 2;
-	  break;
-	}
-	if (*fmt == '0')
-	  zero = 1;
-	state = 2;
-      case 2:
-	if (*fmt >= '0' && *fmt <= '9') {
-	  width = width * 10 + *fmt++ - '0';
-	  break;
-	}
-	state = 3;
-      case 3:
-	if (*fmt == 'l') {
-	  ++ll;
-	  ++fmt;
-	  break;
-	}
-	state = 4;
-      case 4:
-	switch (*fmt) {
-	  case 's':
-	    myvsnprintf_string(&dest,de,va_arg(ap,const char *));
-	    break;
-	  case 'd':
-	    switch (ll) {
-	      case 0:
-		myvsnprintf_int(&dest,de,width,zero,neg,10,'a',va_arg(ap,int));
-		break;
-	      case 1:
-		myvsnprintf_int(&dest,de,width,zero,neg,10,'a',va_arg(ap,long));
-		break;
-	      case 2:
-		myvsnprintf_int(&dest,de,width,zero,neg,10,'a',va_arg(ap,longlong));
-		break;
-	    }
-	    break;
-	  case 'u':
-	    switch (ll) {
-	      case 0:
-		myvsnprintf_uint(&dest,de,width,zero,neg,10,'a',va_arg(ap,unsigned int));
-		break;
-	      case 1:
-		myvsnprintf_uint(&dest,de,width,zero,neg,10,'a',va_arg(ap,unsigned long));
-		break;
-	      case 2:
-		myvsnprintf_uint(&dest,de,width,zero,neg,10,'a',va_arg(ap,ulonglong));
-		break;
-	    }
-	    break;
-	  case 'x':
-	    switch (ll) {
-	      case 0:
-		myvsnprintf_uint(&dest,de,width,zero,neg,16,'a',va_arg(ap,unsigned int));
-		break;
-	      case 1:
-		myvsnprintf_uint(&dest,de,width,zero,neg,16,'a',va_arg(ap,unsigned long));
-		break;
-	      case 2:
-		myvsnprintf_uint(&dest,de,width,zero,neg,16,'a',va_arg(ap,ulonglong));
-		break;
-	    }
-	    break;
-	  case 'X':
-	    switch (ll) {
-	      case 0:
-		myvsnprintf_uint(&dest,de,width,zero,neg,16,'A',va_arg(ap,unsigned int));
-		break;
-	      case 1:
-		myvsnprintf_uint(&dest,de,width,zero,neg,16,'A',va_arg(ap,unsigned long));
-		break;
-	      case 2:
-		myvsnprintf_uint(&dest,de,width,zero,neg,16,'A',va_arg(ap,ulonglong));
-		break;
-	    }
-	    break;
-	  default:
-	    break;
-	}
-	++fmt;
-	state = 0;
-	break;
-      default:
-	state = 0;
-	break;
-    }
-  *dest = '\0';
-}
-
-static void   errorjmp(MatroskaFile *mf,const char *fmt, ...) {
-  va_list   ap;
-
-  va_start(ap, fmt);
-  myvsnprintf(mf->errmsg,sizeof(mf->errmsg),fmt,ap);
-  va_end(ap);
-
-  mf->flags |= MPF_ERROR;
-
-  longjmp(mf->jb,1);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// arrays
-static void *ArrayAlloc(MatroskaFile *mf,void **base,
-			unsigned *cur,unsigned *max,unsigned elem_size)
-{
-  if (*cur>=*max) {
-    void      *np;
-    unsigned  newsize = *max * 2;
-    if (newsize==0)
-      newsize = 1;
-
-    np = mf->cache->memrealloc(mf->cache,*base,newsize*elem_size);
-    if (np==NULL)
-      errorjmp(mf,"Out of memory in ArrayAlloc");
-
-    *base = np;
-    *max = newsize;
-  }
-
-  return (char*)*base + elem_size * (*cur)++;
-}
-
-static void ArrayReleaseMemory(MatroskaFile *mf,void **base,
-			       unsigned cur,unsigned *max,unsigned elem_size)
-{
-  if (cur<*max) {
-    void  *np = mf->cache->memrealloc(mf->cache,*base,cur*elem_size);
-    *base = np;
-    *max = cur;
-  }
-}
-
-
-#define	ASGET(f,s,name)	  ArrayAlloc((f),(void**)&(s)->name,&(s)->n##name,&(s)->n##name##Size,sizeof(*((s)->name)))
-#define	AGET(f,name)	  ArrayAlloc((f),(void**)&(f)->name,&(f)->n##name,&(f)->n##name##Size,sizeof(*((f)->name)))
-#define	ARELEASE(f,s,name)  ArrayReleaseMemory((f),(void**)&(s)->name,(s)->n##name,&(s)->n##name##Size,sizeof(*((s)->name)))
-
-///////////////////////////////////////////////////////////////////////////
-// queues
-static struct QueueEntry *QPut(struct Queue *q,struct QueueEntry *qe) {
-  if (q->tail)
-    q->tail->next = qe;
-  qe->next = NULL;
-  q->tail = qe;
-  if (q->head==NULL)
-    q->head = qe;
-
-  return qe;
-}
-
-static struct QueueEntry  *QGet(struct Queue *q) {
-  struct QueueEntry   *qe = q->head;
-  if (qe == NULL)
-    return NULL;
-  q->head = qe->next;
-  if (q->tail == qe)
-    q->tail = NULL;
-  return qe;
-}
-
-static struct QueueEntry  *QAlloc(MatroskaFile *mf) {
-  struct QueueEntry   *qe,**qep;
-  if (mf->QFreeList == NULL) {
-    unsigned	      i;
-
-    qep = AGET(mf,QBlocks);
-
-    *qep = mf->cache->memalloc(mf->cache,QSEGSIZE * sizeof(*qe));
-    if (*qep == NULL)
-      errorjmp(mf,"Ouf of memory");
-
-    qe = *qep;
-
-    for (i=0;i<QSEGSIZE-1;++i)
-      qe[i].next = qe+i+1;
-    qe[QSEGSIZE-1].next = NULL;
-
-    mf->QFreeList = qe;
-  }
-
-  qe = mf->QFreeList;
-  mf->QFreeList = qe->next;
-
-  return qe;
-}
-
-static inline void QFree(MatroskaFile *mf,struct QueueEntry *qe) {
-  qe->next = mf->QFreeList;
-  mf->QFreeList = qe;
-}
-
-// fill the buffer at current position
-static void fillbuf(MatroskaFile *mf) {
-  int	    rd;
-
-  // advance buffer pointers
-  mf->bufbase += mf->buflen;
-  mf->buflen = mf->bufpos = 0;
-
-  // get the relevant page
-  rd = mf->cache->read(mf->cache, mf->bufbase, mf->inbuf, IBSZ);
-  if (rd<0)
-    errorjmp(mf,"I/O Error: %s",mf->cache->geterror(mf->cache));
-
-  mf->buflen = rd;
-}
-
-// fill the buffer and return next char
-static int  nextbuf(MatroskaFile *mf) {
-  fillbuf(mf);
-
-  if (mf->bufpos < mf->buflen)
-    return (unsigned char)(mf->inbuf[mf->bufpos++]);
-
-  return EOF;
-}
-
-static inline int readch(MatroskaFile *mf) {
-  return mf->bufpos < mf->buflen ? (unsigned char)(mf->inbuf[mf->bufpos++]) : nextbuf(mf);
-}
-
-static inline ulonglong	filepos(MatroskaFile *mf) {
-  return mf->bufbase + mf->bufpos;
-}
-
-static void   readbytes(MatroskaFile *mf,void *buffer,int len) {
-  char	*cp = buffer;
-  int	nb = mf->buflen - mf->bufpos;
-
-  if (nb > len)
-    nb = len;
-
-  memcpy(cp, mf->inbuf + mf->bufpos, nb);
-  mf->bufpos += nb;
-  len -= nb;
-  cp += nb;
-
-  if (len>0) {
-    mf->bufbase += mf->buflen;
-    mf->bufpos = mf->buflen = 0;
-
-    nb = mf->cache->read(mf->cache, mf->bufbase, cp, len);
-    if (nb<0)
-      errorjmp(mf,"I/O Error: %s",mf->cache->geterror(mf->cache));
-    if (nb != len)
-      errorjmp(mf,"Short read: got %d bytes of %d",nb,len);
-    mf->bufbase += len;
-  }
-}
-
-static void   skipbytes(MatroskaFile *mf,ulonglong len) {
-  int	    nb = mf->buflen - mf->bufpos;
-
-  if (nb > len)
-    nb = (int)len;
-
-  mf->bufpos += nb;
-  len -= nb;
-
-  if (len>0) {
-    mf->bufbase += mf->buflen;
-    mf->bufpos = mf->buflen = 0;
-
-    mf->bufbase += len;
-  }
-}
-
-static void seek(MatroskaFile *mf,ulonglong pos) {
-  // see if pos is inside buffer
-  if (pos>=mf->bufbase && pos<mf->bufbase+mf->buflen)
-    mf->bufpos = (unsigned)(pos - mf->bufbase);
-  else {
-    // invalidate buffer and set pointer
-    mf->bufbase = pos;
-    mf->buflen = mf->bufpos = 0;
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// floating point
-static inline MKFLOAT	mkfi(int i) {
-#ifdef MATROSKA_INTEGER_ONLY
-  MKFLOAT  f;
-  f.v = (longlong)i << 32;
-  return f;
-#else
-  return i;
-#endif
-}
-
-static inline longlong mul3(MKFLOAT scale,longlong tc) {
-#ifdef MATROSKA_INTEGER_ONLY
-  //             x1 x0
-  //             y1 y0
-  //    --------------
-  //             x0*y0
-  //          x1*y0
-  //          x0*y1
-  //       x1*y1
-  //    --------------
-  //       .. r1 r0 ..
-  //
-  //    r = ((x0*y0) >> 32) + (x1*y0) + (x0*y1) + ((x1*y1) << 32)
-  unsigned    x0,x1,y0,y1;
-  ulonglong   p;
-  char	      sign = 0;
-
-  if (scale.v < 0)
-    sign = !sign, scale.v = -scale.v;
-  if (tc < 0)
-    sign = !sign, tc = -tc;
-
-  x0 = (unsigned)scale.v;
-  x1 = (unsigned)((ulonglong)scale.v >> 32);
-  y0 = (unsigned)tc;
-  y1 = (unsigned)((ulonglong)tc >> 32);
-
-  p = (ulonglong)x0*y0 >> 32;
-  p += (ulonglong)x0*y1;
-  p += (ulonglong)x1*y0;
-  p += (ulonglong)(x1*y1) << 32;
-
-  return p;
-#else
-  return (longlong)(scale * tc);
-#endif
-}
-
-///////////////////////////////////////////////////////////////////////////
-// EBML support
-static int   readID(MatroskaFile *mf) {
-  int	c1,c2,c3,c4;
-
-  c1 = readch(mf);
-  if (c1 == EOF)
-    return EOF;
-
-  if (c1 & 0x80)
-    return c1;
-
-  if ((c1 & 0xf0) == 0)
-    errorjmp(mf,"Invalid first byte of EBML ID: %02X",c1);
-
-  c2 = readch(mf);
-  if (c2 == EOF)
-fail:
-    errorjmp(mf,"Got EOF while reading EBML ID");
-
-  if ((c1 & 0xc0) == 0x40)
-    return (c1<<8) | c2;
-
-  c3 = readch(mf);
-  if (c3 == EOF)
-    goto fail;
-
-  if ((c1 & 0xe0) == 0x20)
-    return (c1<<16) | (c2<<8) | c3;
-
-  c4 = readch(mf);
-  if (c4 == EOF)
-    goto fail;
-
-  if ((c1 & 0xf0) == 0x10)
-    return (c1<<24) | (c2<<16) | (c3<<8) | c4;
-
-  return 0; // NOT REACHED
-}
-
-static ulonglong readVLUIntImp(MatroskaFile *mf,int *mask) {
-  int		c,d,m;
-  ulonglong	v = 0;
-
-  c = readch(mf);
-  if (c == EOF)
-    return 0; // XXX should errorjmp()?
-
-  if (c == 0)
-    errorjmp(mf,"Invalid first byte of EBML integer: 0");
-
-  for (m=0;;++m) {
-    if (c & (0x80 >> m)) {
-      c &= 0x7f >> m;
-      if (mask)
-	*mask = m;
-      return v | ((ulonglong)c << m*8);
-    }
-    d = readch(mf);
-    if (d == EOF)
-      errorjmp(mf,"Got EOF while reading EBML unsigned integer");
-    v = (v<<8) | d;
-  }
-  // NOT REACHED
-}
-
-static inline ulonglong	readVLUInt(MatroskaFile *mf) {
-  return readVLUIntImp(mf,NULL);
-}
-
-static ulonglong	readSizeUnspec(MatroskaFile *mf) {
-  int	    m;
-  ulonglong v = readVLUIntImp(mf,&m);
-
-  // see if it's unspecified
-  if (v == (MAXU64 >> (57-m*7)))
-    return MAXU64;
-
-  return v;
-}
-
-static ulonglong	readSize(MatroskaFile *mf) {
-  ulonglong v = readSizeUnspec(mf);
-
-  // see if it's unspecified
-  if (v == MAXU64)
-    errorjmp(mf,"Unspecified element size is not supported here.");
-
-  return v;
-}
-
-static inline longlong	readVLSInt(MatroskaFile *mf) {
-  static longlong bias[8] = { (ONE<<6)-1, (ONE<<13)-1, (ONE<<20)-1, (ONE<<27)-1,
-			      (ONE<<34)-1, (ONE<<41)-1, (ONE<<48)-1, (ONE<<55)-1 };
-
-  int	    m;
-  longlong  v = readVLUIntImp(mf,&m);
-
-  return v - bias[m];
-}
-
-static ulonglong  readUInt(MatroskaFile *mf,unsigned int len) {
-  int		c;
-  unsigned int	m = len;
-  ulonglong	v = 0;
-
-  if (len==0)
-    return v;
-  if (len>8)
-    errorjmp(mf,"Unsupported integer size in readUInt: %u",len);
-
-  do {
-    c = readch(mf);
-    if (c == EOF)
-      errorjmp(mf,"Got EOF while reading EBML unsigned integer");
-    v = (v<<8) | c;
-  } while (--m);
-
-  return v;
-}
-
-static inline longlong	readSInt(MatroskaFile *mf,unsigned int len) {
-  longlong	v = readUInt(mf,(unsigned)len);
-  int		s = 64 - (len<<3);
-  return (v << s) >> s;
-}
-
-static MKFLOAT readFloat(MatroskaFile *mf,unsigned int len) {
-#ifdef MATROSKA_INTEGER_ONLY
-  MKFLOAT	  f;
-  int		  shift;
-#else
-  union {
-    unsigned int  ui;
-    ulonglong	  ull;
-    float	  f;
-    double	  d;
-  } u;
-#endif
-
-  if (len!=4 && len!=8)
-    errorjmp(mf,"Invalid float size in readFloat: %u",len);
-
-#ifdef MATROSKA_INTEGER_ONLY
-  if (len == 4) {
-    unsigned  ui = (unsigned)readUInt(mf,(unsigned)len);
-    f.v = (ui & 0x7fffff) | 0x800000;
-    if (ui & 0x80000000)
-      f.v = -f.v;
-    shift = (ui >> 23) & 0xff;
-    if (shift == 0) // assume 0
-zero:
-      shift = 0, f.v = 0;
-    else if (shift == 255)
-inf:
-      if (ui & 0x80000000)
-	f.v = LL(0x8000000000000000);
-      else
-	f.v = LL(0x7fffffffffffffff);
-    else {
-      shift += -127 + 9;
-      if (shift > 39)
-	goto inf;
-shift:
-      if (shift < 0)
-	f.v = f.v >> -shift;
-      else if (shift > 0)
-	f.v = f.v << shift;
-    }
-  } else if (len == 8) {
-    ulonglong  ui = readUInt(mf,(unsigned)len);
-    f.v = (ui & LL(0xfffffffffffff)) | LL(0x10000000000000);
-    if (ui & 0x80000000)
-      f.v = -f.v;
-    shift = (int)((ui >> 52) & 0x7ff);
-    if (shift == 0) // assume 0
-      goto zero;
-    else if (shift == 2047)
-      goto inf;
-    else {
-      shift += -1023 - 20;
-      if (shift > 10)
-	goto inf;
-      goto shift;
-    }
-  }
-
-  return f;
-#else
-  if (len==4) {
-    u.ui = (unsigned int)readUInt(mf,(unsigned)len);
-    return u.f;
-  }
-
-  if (len==8) {
-    u.ull = readUInt(mf,(unsigned)len);
-    return u.d;
-  }
-
-  return 0;
-#endif
-}
-
-static void readString(MatroskaFile *mf,ulonglong len,char *buffer,int buflen) {
-  int	  nread;
-
-  if (buflen<1)
-    errorjmp(mf,"Invalid buffer size in readString: %d",buflen);
-
-  nread = buflen - 1;
-
-  if (nread > len)
-    nread = (int)len;
-
-  readbytes(mf,buffer,nread);
-  len -= nread;
-
-  if (len>0)
-    skipbytes(mf,len);
-
-  buffer[nread] = '\0';
-}
-
-static void readLangCC(MatroskaFile *mf, ulonglong len, char lcc[4]) {
-  unsigned  todo = len > 3 ? 3 : (int)len;
-
-  lcc[0] = lcc[1] = lcc[2] = lcc[3] = 0;
-  readbytes(mf, lcc, todo);
-  skipbytes(mf, len - todo);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// file parser
-#define	FOREACH2(f,tl,clid) \
-  { \
-    ulonglong	tmplen = (tl); \
-    { \
-      ulonglong   start = filepos(f); \
-      ulonglong   cur,len; \
-      int	      id; \
-      for (;;) { \
-	cur = filepos(mf); \
-	if (tmplen != MAXU64 && cur == start + tmplen) \
-	  break; \
-	id = readID(f); \
-	if (id==EOF) \
-	  errorjmp(mf,"Unexpected EOF while reading EBML container"); \
-        len = id == clid ? readSizeUnspec(mf) : readSize(mf); \
-	switch (id) {
-
-#define FOREACH(f,tl) FOREACH2(f,tl,EOF)
-
-#define RESTART()     (tmplen=len),(start=cur)
-
-#define	ENDFOR1(f) \
-	default: \
-	  skipbytes(f,len); \
-	  break; \
-	}
-#define	ENDFOR2() \
-      } \
-    } \
-  }
-
-#define	ENDFOR(f) ENDFOR1(f) ENDFOR2()
-
-#define	myalloca(f,c) alloca(c)
-#define	STRGETF(f,v,len,func) \
-  { \
-    char *TmpVal; \
-    unsigned TmpLen = (len)>MAX_STRING_LEN ? MAX_STRING_LEN : (unsigned)(len); \
-    TmpVal = func(f->cache,TmpLen+1); \
-    if (TmpVal == NULL) \
-      errorjmp(mf,"Out of memory"); \
-    readString(f,len,TmpVal,TmpLen+1); \
-    (v) = TmpVal; \
-  }
-
-#define	STRGETA(f,v,len)  STRGETF(f,v,len,myalloca)
-#define	STRGETM(f,v,len)  STRGETF(f,v,len,f->cache->memalloc)
-
-static int  IsWritingApp(MatroskaFile *mf,const char *str) {
-  const char  *cp = mf->Seg.WritingApp;
-  if (!cp)
-    return 0;
-
-  while (*str && *str++==*cp++) ;
-
-  return !*str;
-}
-
-static void parseEBML(MatroskaFile *mf,ulonglong toplen) {
-  ulonglong v;
-  char	    buf[32];
-
-  FOREACH(mf,toplen)
-    case 0x4286: // Version
-      v = readUInt(mf,(unsigned)len);
-      break;
-    case 0x42f7: // ReadVersion
-      v = readUInt(mf,(unsigned)len);
-      if (v > EBML_VERSION)
-	errorjmp(mf,"File requires version %d EBML parser",(int)v);
-      break;
-    case 0x42f2: // MaxIDLength
-      v = readUInt(mf,(unsigned)len);
-      if (v > EBML_MAX_ID_LENGTH)
-	errorjmp(mf,"File has identifiers longer than %d",(int)v);
-      break;
-    case 0x42f3: // MaxSizeLength
-      v = readUInt(mf,(unsigned)len);
-      if (v > EBML_MAX_SIZE_LENGTH)
-	errorjmp(mf,"File has integers longer than %d",(int)v);
-      break;
-    case 0x4282: // DocType
-      readString(mf,len,buf,sizeof(buf));
-      if (strcmp(buf,MATROSKA_DOCTYPE))
-	errorjmp(mf,"Unsupported DocType: %s",buf);
-      break;
-    case 0x4287: // DocTypeVersion
-      v = readUInt(mf,(unsigned)len);
-      break;
-    case 0x4285: // DocTypeReadVersion
-      v = readUInt(mf,(unsigned)len);
-      if (v > MATROSKA_VERSION)
-	errorjmp(mf,"File requires version %d Matroska parser",(int)v);
-      break;
-  ENDFOR(mf);
-}
-
-static void parseSeekEntry(MatroskaFile *mf,ulonglong toplen) {
-  int	    seekid = 0;
-  ulonglong pos = (ulonglong)-1;
-
-  FOREACH(mf,toplen)
-    case 0x53ab: // SeekID
-      if (len>EBML_MAX_ID_LENGTH)
-	errorjmp(mf,"Invalid ID size in parseSeekEntry: %d\n",(int)len);
-      seekid = (int)readUInt(mf,(unsigned)len);
-      break;
-    case 0x53ac: // SeekPos
-      pos = readUInt(mf,(unsigned)len);
-      break;
-  ENDFOR(mf);
-
-  if (pos == (ulonglong)-1)
-    errorjmp(mf,"Invalid element position in parseSeekEntry");
-
-  pos += mf->pSegment;
-  switch (seekid) {
-    case 0x114d9b74: // next SeekHead
-      if (mf->pSeekHead)
-	errorjmp(mf,"SeekHead contains more than one SeekHead pointer");
-      mf->pSeekHead = pos;
-      break;
-    case 0x1549a966: // SegmentInfo
-      mf->pSegmentInfo = pos;
-      break;
-    case 0x1f43b675: // Cluster
-      if (!mf->pCluster)
-	mf->pCluster = pos;
-      break;
-    case 0x1654ae6b: // Tracks
-      mf->pTracks = pos;
-      break;
-    case 0x1c53bb6b: // Cues
-      mf->pCues = pos;
-      break;
-    case 0x1941a469: // Attachments
-      mf->pAttachments = pos;
-      break;
-    case 0x1043a770: // Chapters
-      mf->pChapters = pos;
-      break;
-    case 0x1254c367: // tags
-      mf->pTags = pos;
-      break;
-  }
-}
-
-static void parseSeekHead(MatroskaFile *mf,ulonglong toplen) {
-  FOREACH(mf,toplen)
-    case 0x4dbb:
-      parseSeekEntry(mf,len);
-      break;
-  ENDFOR(mf);
-}
-
-static void parseSegmentInfo(MatroskaFile *mf,ulonglong toplen) {
-  MKFLOAT     duration = mkfi(0);
-
-  if (mf->seen.SegmentInfo) {
-    skipbytes(mf,toplen);
-    return;
-  }
-
-  mf->seen.SegmentInfo = 1;
-  mf->Seg.TimecodeScale = 1000000; // Default value
-
-  FOREACH(mf,toplen)
-    case 0x73a4: // SegmentUID
-      if (len!=sizeof(mf->Seg.UID))
-	errorjmp(mf,"SegmentUID size is not %d bytes",mf->Seg.UID);
-      readbytes(mf,mf->Seg.UID,sizeof(mf->Seg.UID));
-      break;
-    case 0x7384: // SegmentFilename
-      STRGETM(mf,mf->Seg.Filename,len);
-      break;
-    case 0x3cb923: // PrevUID
-      if (len!=sizeof(mf->Seg.PrevUID))
-	errorjmp(mf,"PrevUID size is not %d bytes",mf->Seg.PrevUID);
-      readbytes(mf,mf->Seg.PrevUID,sizeof(mf->Seg.PrevUID));
-      break;
-    case 0x3c83ab: // PrevFilename
-      STRGETM(mf,mf->Seg.PrevFilename,len);
-      break;
-    case 0x3eb923: // NextUID
-      if (len!=sizeof(mf->Seg.NextUID))
-	errorjmp(mf,"NextUID size is not %d bytes",mf->Seg.NextUID);
-      readbytes(mf,mf->Seg.NextUID,sizeof(mf->Seg.NextUID));
-      break;
-    case 0x3e83bb: // NextFilename
-      STRGETM(mf,mf->Seg.NextFilename,len);
-      break;
-    case 0x2ad7b1: // TimecodeScale
-      mf->Seg.TimecodeScale = readUInt(mf,(unsigned)len);
-      if (mf->Seg.TimecodeScale == 0)
-	errorjmp(mf,"Segment timecode scale is zero");
-      break;
-    case 0x4489: // Duration
-      duration = readFloat(mf,(unsigned)len);
-      break;
-    case 0x4461: // DateUTC
-      mf->Seg.DateUTC = readUInt(mf,(unsigned)len);
-      mf->Seg.DateUTCValid = 1;
-      break;
-    case 0x7ba9: // Title
-      STRGETM(mf,mf->Seg.Title,len);
-      break;
-    case 0x4d80: // MuxingApp
-      STRGETM(mf,mf->Seg.MuxingApp,len);
-      break;
-    case 0x5741: // WritingApp
-      STRGETM(mf,mf->Seg.WritingApp,len);
-      break;
-  ENDFOR(mf);
-
-  mf->Seg.Duration = mul3(duration,mf->Seg.TimecodeScale);
-}
-
-static void parseFirstCluster(MatroskaFile *mf,ulonglong toplen) {
-  int       seenTimecode = 0, seenBlock = 0;
-  longlong  tc;
-  ulonglong clstart = filepos(mf);
-
-  mf->seen.Cluster = 1;
-  mf->firstTimecode = 0;
-
-  FOREACH2(mf,toplen,0x1f43b675)
-    case 0xe7: // Timecode
-      tc = readUInt(mf,(unsigned)len);
-      if (!seenTimecode) {
-        seenTimecode = 1;
-        mf->firstTimecode += tc;
-      }
-
-      if (seenBlock) {
-out:
-        if (toplen != MAXU64)
-          skipbytes(mf,clstart + toplen - filepos(mf));
-        else if (len != MAXU64)
-          skipbytes(mf,cur + len - filepos(mf));
-        return;
-      }
-      break;
-    case 0xa3: // BlockEx
-      readVLUInt(mf); // track number
-      tc = readSInt(mf, 2);
-      if (!seenBlock) {
-        seenBlock = 1;
-        mf->firstTimecode += tc;
-      }
-
-      if (seenTimecode)
-        goto out;
-      break;
-    case 0xa0: // BlockGroup
-      FOREACH(mf,len)
-	case 0xa1: // Block
-	  readVLUInt(mf); // track number
-	  tc = readSInt(mf,2); 
-          if (!seenBlock) {
-            seenBlock = 1;
-            mf->firstTimecode += tc;
-          }
-
-          if (seenTimecode)
-            goto out;
-      ENDFOR(mf);
-      break;
-    case 0x1f43b675:
-      return;
-  ENDFOR(mf);
-}
-
-static void parseVideoInfo(MatroskaFile *mf,ulonglong toplen,struct TrackInfo *ti) {
-  ulonglong v;
-  char	    dW = 0, dH = 0;
-
-  FOREACH(mf,toplen)
-    case 0x9a: // FlagInterlaced
-      ti->AV.Video.Interlaced = readUInt(mf,(unsigned)len)!=0;
-      break;
-    case 0x53b8: // StereoMode
-      v = readUInt(mf,(unsigned)len);
-      if (v>3)
-	errorjmp(mf,"Invalid stereo mode");
-      ti->AV.Video.StereoMode = (unsigned char)v;
-      break;
-    case 0xb0: // PixelWidth
-      v = readUInt(mf,(unsigned)len);
-      if (v>0xffffffff)
-	errorjmp(mf,"PixelWidth is too large");
-      ti->AV.Video.PixelWidth = (unsigned)v;
-      if (!dW)
-	ti->AV.Video.DisplayWidth = ti->AV.Video.PixelWidth;
-      break;
-    case 0xba: // PixelHeight
-      v = readUInt(mf,(unsigned)len);
-      if (v>0xffffffff)
-	errorjmp(mf,"PixelHeight is too large");
-      ti->AV.Video.PixelHeight = (unsigned)v;
-      if (!dH)
-	ti->AV.Video.DisplayHeight = ti->AV.Video.PixelHeight;
-      break;
-    case 0x54b0: // DisplayWidth
-      v = readUInt(mf,(unsigned)len);
-      if (v>0xffffffff)
-	errorjmp(mf,"DisplayWidth is too large");
-      ti->AV.Video.DisplayWidth = (unsigned)v;
-      dW = 1;
-      break;
-    case 0x54ba: // DisplayHeight
-      v = readUInt(mf,(unsigned)len);
-      if (v>0xffffffff)
-	errorjmp(mf,"DisplayHeight is too large");
-      ti->AV.Video.DisplayHeight = (unsigned)v;
-      dH = 1;
-      break;
-    case 0x54b2: // DisplayUnit
-      v = readUInt(mf,(unsigned)len);
-      if (v>2)
-	errorjmp(mf,"Invalid DisplayUnit: %d",(int)v);
-      ti->AV.Video.DisplayUnit = (unsigned char)v;
-      break;
-    case 0x54b3: // AspectRatioType
-      v = readUInt(mf,(unsigned)len);
-      if (v>2)
-	errorjmp(mf,"Invalid AspectRatioType: %d",(int)v);
-      ti->AV.Video.AspectRatioType = (unsigned char)v;
-      break;
-    case 0x54aa: // PixelCropBottom
-      v = readUInt(mf,(unsigned)len);
-      if (v>0xffffffff)
-	errorjmp(mf,"PixelCropBottom is too large");
-      ti->AV.Video.CropB = (unsigned)v;
-      break;
-    case 0x54bb: // PixelCropTop
-      v = readUInt(mf,(unsigned)len);
-      if (v>0xffffffff)
-	errorjmp(mf,"PixelCropTop is too large");
-      ti->AV.Video.CropT = (unsigned)v;
-      break;
-    case 0x54cc: // PixelCropLeft
-      v = readUInt(mf,(unsigned)len);
-      if (v>0xffffffff)
-	errorjmp(mf,"PixelCropLeft is too large");
-      ti->AV.Video.CropL = (unsigned)v;
-      break;
-    case 0x54dd: // PixelCropRight
-      v = readUInt(mf,(unsigned)len);
-      if (v>0xffffffff)
-	errorjmp(mf,"PixelCropRight is too large");
-      ti->AV.Video.CropR = (unsigned)v;
-      break;
-    case 0x2eb524: // ColourSpace
-      ti->AV.Video.ColourSpace = (unsigned)readUInt(mf,4);
-      break;
-    case 0x2fb523: // GammaValue
-      ti->AV.Video.GammaValue = readFloat(mf,(unsigned)len);
-      break;
-  ENDFOR(mf);
-}
-
-static void parseAudioInfo(MatroskaFile *mf,ulonglong toplen,struct TrackInfo *ti) {
-  ulonglong   v;
-
-  FOREACH(mf,toplen)
-    case 0xb5: // SamplingFrequency
-      ti->AV.Audio.SamplingFreq = readFloat(mf,(unsigned)len);
-      break;
-    case 0x78b5: // OutputSamplingFrequency
-      ti->AV.Audio.OutputSamplingFreq = readFloat(mf,(unsigned)len);
-      break;
-    case 0x9f: // Channels
-      v = readUInt(mf,(unsigned)len);
-      if (v<1 || v>255)
-	errorjmp(mf,"Invalid Channels value");
-      ti->AV.Audio.Channels = (unsigned char)v;
-      break;
-    case 0x7d7b: // ChannelPositions
-      skipbytes(mf,len);
-      break;
-    case 0x6264: // BitDepth
-      v = readUInt(mf,(unsigned)len);
-#if 0
-      if ((v<1 || v>255) && !IsWritingApp(mf,"AVI-Mux GUI"))
-	errorjmp(mf,"Invalid BitDepth: %d",(int)v);
-#endif
-      ti->AV.Audio.BitDepth = (unsigned char)v;
-      break;
-  ENDFOR(mf);
-
-  if (ti->AV.Audio.Channels == 0)
-    ti->AV.Audio.Channels = 1;
-  if (mkv_TruncFloat(ti->AV.Audio.SamplingFreq) == 0)
-    ti->AV.Audio.SamplingFreq = mkfi(8000);
-  if (mkv_TruncFloat(ti->AV.Audio.OutputSamplingFreq)==0)
-    ti->AV.Audio.OutputSamplingFreq = ti->AV.Audio.SamplingFreq;
-}
-
-static void CopyStr(char **src,char **dst) {
-  size_t l;
-
-  if (!*src)
-    return;
-
-  l = strlen(*src)+1;
-  memcpy(*dst,*src,l);
-  *src = *dst;
-  *dst += l;
-}
-
-static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
-  struct TrackInfo  t,*tp,**tpp;
-  ulonglong	    v;
-  char		    *cp = NULL, *cs = NULL;
-  size_t	    cplen = 0, cslen = 0, cpadd = 0;
-  unsigned	    CompScope, num_comp = 0;
-
-  if (mf->nTracks >= MAX_TRACKS)
-    errorjmp(mf,"Too many tracks.");
-
-  // clear track info
-  memset(&t,0,sizeof(t));
-
-  // fill default values
-  t.Enabled = 1;
-  t.Default = 1;
-  t.Lacing = 1;
-  t.TimecodeScale = mkfi(1);
-  t.DecodeAll = 1;
-
-  FOREACH(mf,toplen)
-    case 0xd7: // TrackNumber
-      v = readUInt(mf,(unsigned)len);
-      if (v>255)
-	errorjmp(mf,"Track number is >255 (%d)",(int)v);
-      t.Number = (unsigned char)v;
-      break;
-    case 0x73c5: // TrackUID
-      t.UID = readUInt(mf,(unsigned)len);
-      break;
-    case 0x83: // TrackType
-      v = readUInt(mf,(unsigned)len);
-      if (v<1 || v>254)
-	errorjmp(mf,"Invalid track type: %d",(int)v);
-      t.Type = (unsigned char)v;
-      break;
-    case 0xb9: // Enabled
-      t.Enabled = readUInt(mf,(unsigned)len)!=0;
-      break;
-    case 0x88: // Default
-      t.Default = readUInt(mf,(unsigned)len)!=0;
-      break;
-    case 0x9c: // Lacing
-      t.Lacing = readUInt(mf,(unsigned)len)!=0;
-      break;
-    case 0x6de7: // MinCache
-      v = readUInt(mf,(unsigned)len);
-      if (v > 0xffffffff)
-	errorjmp(mf,"MinCache is too large");
-      t.MinCache = (unsigned)v;
-      break;
-    case 0x6df8: // MaxCache
-      v = readUInt(mf,(unsigned)len);
-      if (v > 0xffffffff)
-	errorjmp(mf,"MaxCache is too large");
-      t.MaxCache = (unsigned)v;
-      break;
-    case 0x23e383: // DefaultDuration
-      t.DefaultDuration = readUInt(mf,(unsigned)len);
-      break;
-    case 0x23314f: // TrackTimecodeScale
-      t.TimecodeScale = readFloat(mf,(unsigned)len);
-      break;
-    case 0x55ee: // MaxBlockAdditionID
-      t.MaxBlockAdditionID = (unsigned)readUInt(mf,(unsigned)len);
-      break;
-    case 0x536e: // Name
-      if (t.Name)
-	errorjmp(mf,"Duplicate Track Name");
-      STRGETA(mf,t.Name,len);
-      break;
-    case 0x22b59c: // Language
-      readLangCC(mf, len, t.Language);
-      break;
-    case 0x86: // CodecID
-      if (t.CodecID)
-	errorjmp(mf,"Duplicate CodecID");
-      STRGETA(mf,t.CodecID,len);
-      break;
-    case 0x63a2: // CodecPrivate
-      if (cp)
-	errorjmp(mf,"Duplicate CodecPrivate");
-      if (len>262144) // 256KB
-	errorjmp(mf,"CodecPrivate is too large: %d",(int)len);
-      cplen = (unsigned)len;
-      cp = alloca(cplen);
-      readbytes(mf,cp,(int)cplen);
-      break;
-    case 0x258688: // CodecName
-      skipbytes(mf,len);
-      break;
-    case 0x3a9697: // CodecSettings
-      skipbytes(mf,len);
-      break;
-    case 0x3b4040: // CodecInfoURL
-      skipbytes(mf,len);
-      break;
-    case 0x26b240: // CodecDownloadURL
-      skipbytes(mf,len);
-      break;
-    case 0xaa: // CodecDecodeAll
-      t.DecodeAll = readUInt(mf,(unsigned)len)!=0;
-      break;
-    case 0x6fab: // TrackOverlay
-      v = readUInt(mf,(unsigned)len);
-      if (v>255)
-	errorjmp(mf,"Track number in TrackOverlay is too large: %d",(int)v);
-      t.TrackOverlay = (unsigned char)v;
-      break;
-    case 0xe0: // VideoInfo
-      parseVideoInfo(mf,len,&t);
-      break;
-    case 0xe1: // AudioInfo
-      parseAudioInfo(mf,len,&t);
-      break;
-    case 0x6d80: // ContentEncodings
-      FOREACH(mf,len)
-	case 0x6240: // ContentEncoding
-          // fill in defaults
-	  t.CompEnabled = 1;
-	  t.CompMethod = COMP_ZLIB;
-	  CompScope = 1;
-	  if (++num_comp > 1)
-	    return; // only one compression layer supported
-	  FOREACH(mf,len)
-	    case 0x5031: // ContentEncodingOrder
-	      readUInt(mf,(unsigned)len);
-	      break;
-	    case 0x5032: // ContentEncodingScope
-	      CompScope = (unsigned)readUInt(mf,(unsigned)len);
-	      break;
-	    case 0x5033: // ContentEncodingType
-	      if (readUInt(mf,(unsigned)len) != 0)
-		return; // encryption is not supported
-	      break;
-	    case 0x5034: // ContentCompression
-	      FOREACH(mf,len)
-		case 0x4254: // ContentCompAlgo
-		  v = readUInt(mf,(unsigned)len);
-		  t.CompEnabled = 1;
-		  switch (v) {
-		    case 0: // Zlib
-		      t.CompMethod = COMP_ZLIB;
-		      break;
-		    case 3: // prepend fixed data
-		      t.CompMethod = COMP_PREPEND;
-		      break;
-		    default:
-		      return; // unsupported compression, skip track
-		  }
-		  break;
-		case 0x4255: // ContentCompSettings
-		  if (len > 256)
-		    return;
-		  cslen = (unsigned)len;
-		  cs = alloca(cslen);
-		  readbytes(mf, cs, (int)cslen);
-		  break;
-	      ENDFOR(mf);
-	      break;
-	      // TODO Implement Encryption/Signatures
-	  ENDFOR(mf);
-	  break;
-      ENDFOR(mf);
-      break;
-  ENDFOR(mf);
-
-  // validate track info
-  if (!t.CodecID)
-    errorjmp(mf,"Track has no Codec ID");
-
-  if (t.UID != 0) {
-    unsigned  i;
-    for (i = 0; i < mf->nTracks; ++i)
-      if (mf->Tracks[i]->UID == t.UID) // duplicate track entry
-	return;
-  }
-
-#ifdef MATROSKA_COMPRESSION_SUPPORT
-  // handle compressed CodecPrivate
-  if (t.CompEnabled && t.CompMethod == COMP_ZLIB && (CompScope & 2) && cplen > 0) {
-    z_stream  zs;
-    Bytef     tmp[64], *ncp;
-    int	      code;
-    uLong     ncplen;
-
-    memset(&zs,0,sizeof(zs));
-    if (inflateInit(&zs) != Z_OK)
-      errorjmp(mf, "inflateInit failed");
-
-    zs.next_in = (Bytef *)cp;
-    zs.avail_in = (uInt)cplen;
-
-    do {
-      zs.next_out = tmp;
-      zs.avail_out = sizeof(tmp);
-
-      code = inflate(&zs, Z_NO_FLUSH);
-    } while (code == Z_OK);
-
-    if (code != Z_STREAM_END)
-      errorjmp(mf, "invalid compressed data in CodecPrivate");
-
-    ncplen = zs.total_out;
-    ncp = alloca(ncplen);
-
-    inflateReset(&zs);
-
-    zs.next_in = (Bytef *)cp;
-    zs.avail_in = (uInt)cplen;
-    zs.next_out = ncp;
-    zs.avail_out = ncplen;
-
-    if (inflate(&zs, Z_FINISH) != Z_STREAM_END)
-      errorjmp(mf, "inflate failed");
-
-    inflateEnd(&zs);
-
-    cp = (char *)ncp;
-    cplen = ncplen;
-  }
-#endif
-
-  if (t.CompEnabled && !(CompScope & 1)) {
-    t.CompEnabled = 0;
-    cslen = 0;
-  }
-
-  // allocate new track
-  tpp = AGET(mf,Tracks);
-
-  // copy strings
-  if (t.Name)
-    cpadd += strlen(t.Name)+1;
-  if (t.CodecID)
-    cpadd += strlen(t.CodecID)+1;
-
-  tp = mf->cache->memalloc(mf->cache,sizeof(*tp) + cplen + cslen + cpadd);
-  if (tp == NULL)
-    errorjmp(mf,"Out of memory");
-
-  memcpy(tp,&t,sizeof(*tp));
-  if (cplen) {
-    tp->CodecPrivate = tp+1;
-    tp->CodecPrivateSize = (unsigned)cplen;
-    memcpy(tp->CodecPrivate,cp,cplen);
-  }
-  if (cslen) {
-    tp->CompMethodPrivate = (char *)(tp+1) + cplen;
-    tp->CompMethodPrivateSize = (unsigned)cslen;
-    memcpy(tp->CompMethodPrivate, cs, cslen);
-  }
-
-  cp = (char*)(tp+1) + cplen + cslen;
-  CopyStr(&tp->Name,&cp);
-  CopyStr(&tp->CodecID,&cp);
-
-  // set default language
-  if (!tp->Language[0])
-    memcpy(tp->Language, "eng", 4);
-
-  *tpp = tp;
-}
-
-static void parseTracks(MatroskaFile *mf,ulonglong toplen) {
-  mf->seen.Tracks = 1;
-  FOREACH(mf,toplen)
-    case 0xae: // TrackEntry
-      parseTrackEntry(mf,len);
-      break;
-  ENDFOR(mf);
-}
-
-static void addCue(MatroskaFile *mf,ulonglong pos,ulonglong timecode) {
-  struct Cue  *cc = AGET(mf,Cues);
-  cc->Time = timecode;
-  cc->Position = pos;
-  cc->Track = 0;
-  cc->Block = 0;
-}
-
-static void fixupCues(MatroskaFile *mf) {
-  // adjust cues, shift cues if file does not start at 0
-  unsigned  i;
-  longlong  adjust = mf->firstTimecode * mf->Seg.TimecodeScale;
-
-  for (i=0;i<mf->nCues;++i) {
-    mf->Cues[i].Time *= mf->Seg.TimecodeScale;
-    mf->Cues[i].Time -= adjust;
-  }
-}
-
-static void parseCues(MatroskaFile *mf,ulonglong toplen) {
-  jmp_buf     jb;
-  ulonglong   v;
-  struct Cue  cc;
-  unsigned    i,j,k;
-
-  mf->seen.Cues = 1;
-  mf->nCues = 0;
-  cc.Block = 0;
-
-  memcpy(&jb,&mf->jb,sizeof(jb));
-
-  if (setjmp(mf->jb)) {
-    memcpy(&mf->jb,&jb,sizeof(jb));
-    mf->nCues = 0;
-    mf->seen.Cues = 0;
-    return;
-  }
-
-  FOREACH(mf,toplen)
-    case 0xbb: // CuePoint
-      FOREACH(mf,len)
-	case 0xb3: // CueTime
-	  cc.Time = readUInt(mf,(unsigned)len);
-	  break;
-	case 0xb7: // CueTrackPositions
-	  FOREACH(mf,len)
-	    case 0xf7: // CueTrack
-	      v = readUInt(mf,(unsigned)len);
-	      if (v>255)
-		errorjmp(mf,"CueTrack points to an invalid track: %d",(int)v);
-	      cc.Track = (unsigned char)v;
-	      break;
-	    case 0xf1: // CueClusterPosition
-	      cc.Position = readUInt(mf,(unsigned)len);
-	      break;
-	    case 0x5378: // CueBlockNumber
-	      cc.Block = readUInt(mf,(unsigned)len);
-	      break;
-	    case 0xea: // CodecState
-	      readUInt(mf,(unsigned)len);
-	      break;
-	    case 0xdb: // CueReference
-	      FOREACH(mf,len)
-		case 0x96: // CueRefTime
-		  readUInt(mf,(unsigned)len);
-		  break;
-		case 0x97: // CueRefCluster
-		  readUInt(mf,(unsigned)len);
-		  break;
-		case 0x535f: // CueRefNumber
-		  readUInt(mf,(unsigned)len);
-		  break;
-		case 0xeb: // CueRefCodecState
-		  readUInt(mf,(unsigned)len);
-		  break;
-	      ENDFOR(mf);
-	      break;
-	  ENDFOR(mf);
-	  break;
-      ENDFOR(mf);
-
-      if (mf->nCues == 0 && mf->pCluster - mf->pSegment != cc.Position)
-	addCue(mf,mf->pCluster - mf->pSegment,mf->firstTimecode);
-
-      memcpy(AGET(mf,Cues),&cc,sizeof(cc));
-      break;
-  ENDFOR(mf);
-
-  memcpy(&mf->jb,&jb,sizeof(jb));
-
-  ARELEASE(mf,mf,Cues);
-
-  // bubble sort the cues and fuck the losers that write unordered cues
-  if (mf->nCues > 0)
-    for (i = mf->nCues - 1, k = 1; i > 0 && k > 0; --i)
-      for (j = k = 0; j < i; ++j)
-	if (mf->Cues[j].Time > mf->Cues[j+1].Time) {
-	  struct Cue tmp = mf->Cues[j+1];
-	  mf->Cues[j+1] = mf->Cues[j];
-	  mf->Cues[j] = tmp;
-	  ++k;
-	}
-}
-
-static void parseAttachment(MatroskaFile *mf,ulonglong toplen) {
-  struct Attachment a,*pa;
-
-  memset(&a,0,sizeof(a));
-  FOREACH(mf,toplen)
-    case 0x467e: // Description
-      STRGETA(mf,a.Description,len);
-      break;
-    case 0x466e: // Name
-      STRGETA(mf,a.Name,len);
-      break;
-    case 0x4660: // MimeType
-      STRGETA(mf,a.MimeType,len);
-      break;
-    case 0x46ae: // UID
-      a.UID = readUInt(mf,(unsigned)len);
-      break;
-    case 0x465c: // Data
-      a.Position = filepos(mf);
-      a.Length = len;
-      skipbytes(mf,len);
-      break;
-  ENDFOR(mf);
-
-  if (!a.Position)
-    return;
-
-  pa = AGET(mf,Attachments);
-  memcpy(pa,&a,sizeof(a));
-
-  if (a.Description)
-    pa->Description = mystrdup(mf->cache,a.Description);
-  if (a.Name)
-    pa->Name = mystrdup(mf->cache,a.Name);
-  if (a.MimeType)
-    pa->MimeType = mystrdup(mf->cache,a.MimeType);
-}
-
-static void parseAttachments(MatroskaFile *mf,ulonglong toplen) {
-  mf->seen.Attachments = 1;
-
-  FOREACH(mf,toplen)
-    case 0x61a7: // AttachedFile
-      parseAttachment(mf,len);
-      break;
-  ENDFOR(mf);
-}
-
-static void parseChapter(MatroskaFile *mf,ulonglong toplen,struct Chapter *parent) {
-  struct ChapterDisplay	*disp;
-  struct ChapterProcess	*proc;
-  struct ChapterCommand	*cmd;
-  struct Chapter	*ch = ASGET(mf,parent,Children);
-
-  memset(ch,0,sizeof(*ch));
-
-  ch->Enabled = 1;
-
-  FOREACH(mf,toplen)
-    case 0x73c4: // ChapterUID
-      ch->UID = readUInt(mf,(unsigned)len);
-      break;
-    case 0x6e67: // ChapterSegmentUID
-      if (len != sizeof(ch->SegmentUID))
-	skipbytes(mf, len);
-      else
-	readbytes(mf, ch->SegmentUID, sizeof(ch->SegmentUID));
-      break;
-    case 0x91: // ChapterTimeStart
-      ch->Start = readUInt(mf,(unsigned)len);
-      break;
-    case 0x92: // ChapterTimeEnd
-      ch->End = readUInt(mf,(unsigned)len);
-      break;
-    case 0x98: // ChapterFlagHidden
-      ch->Hidden = readUInt(mf,(unsigned)len)!=0;
-      break;
-    case 0x4598: // ChapterFlagEnabled
-      ch->Enabled = readUInt(mf,(unsigned)len)!=0;
-      break;
-    case 0x8f: // ChapterTrack
-      FOREACH(mf,len)
-	case 0x89: // ChapterTrackNumber
-	  *(ulonglong*)(ASGET(mf,ch,Tracks)) = readUInt(mf,(unsigned)len);
-	  break;
-      ENDFOR(mf);
-      break;
-    case 0x80: // ChapterDisplay
-      disp = NULL;
-
-      FOREACH(mf,len)
-	case 0x85: // ChapterString
-	  if (disp==NULL) {
-	    disp = ASGET(mf,ch,Display);
-	    memset(disp, 0, sizeof(*disp));
-	  }
-	  if (disp->String)
-	    skipbytes(mf,len); // Ignore duplicate string
-	  else
-	    STRGETM(mf,disp->String,len);
-	  break;
-	case 0x437c: // ChapterLanguage
-	  if (disp==NULL) {
-	    disp = ASGET(mf,ch,Display);
-	    memset(disp, 0, sizeof(*disp));
-	  }
-	  readLangCC(mf, len, disp->Language);
-	  break;
-	case 0x437e: // ChapterCountry
-	  if (disp==NULL) {
-	    disp = ASGET(mf,ch,Display);
-	    memset(disp, 0, sizeof(*disp));
-	  }
-	  readLangCC(mf, len, disp->Country);
-	  break;
-      ENDFOR(mf);
-
-      if (disp && !disp->String)
-	--ch->nDisplay;
-      break;
-    case 0x6944: // ChapProcess
-      proc = NULL;
-
-      FOREACH(mf,len)
-	case 0x6955: // ChapProcessCodecID
-	  if (proc == NULL) {
-	    proc = ASGET(mf, ch, Process);
-	    memset(proc, 0, sizeof(*proc));
-	  }
-	  proc->CodecID = (unsigned)readUInt(mf,(unsigned)len);
-	  break;
-	case 0x450d: // ChapProcessPrivate
-	  if (proc == NULL) {
-	    proc = ASGET(mf, ch, Process);
-	    memset(proc, 0, sizeof(*proc));
-	  }
-	  if (proc->CodecPrivate)
-	    skipbytes(mf, len);
-	  else {
-	    proc->CodecPrivateLength = (unsigned)len;
-	    STRGETM(mf,proc->CodecPrivate,len);
-	  }
-	  break;
-	case 0x6911: // ChapProcessCommand
-	  if (proc == NULL) {
-	    proc = ASGET(mf, ch, Process);
-	    memset(proc, 0, sizeof(*proc));
-	  }
-
-	  cmd = NULL;
-
-	  FOREACH(mf,len)
-	    case 0x6922: // ChapterCommandTime
-	      if (cmd == NULL) {
-		cmd = ASGET(mf,proc,Commands);
-		memset(cmd, 0, sizeof(*cmd));
-	      }
-	      cmd->Time = (unsigned)readUInt(mf,(unsigned)len);
-	      break;
-	    case 0x6933: // ChapterCommandString
-	      if (cmd == NULL) {
-		cmd = ASGET(mf,proc,Commands);
-		memset(cmd, 0, sizeof(*cmd));
-	      }
-	      if (cmd->Command)
-		skipbytes(mf,len);
-	      else {
-		cmd->CommandLength = (unsigned)len;
-		STRGETM(mf,cmd->Command,len);
-	      }
-	      break;
-	  ENDFOR(mf);
-
-	  if (cmd && !cmd->Command)
-	    --proc->nCommands;
-	  break;
-      ENDFOR(mf);
-
-      if (proc && !proc->nCommands)
-	--ch->nProcess;
-      break;
-    case 0xb6: // Nested ChapterAtom
-      parseChapter(mf,len,ch);
-      break;
-  ENDFOR(mf);
-
-  ARELEASE(mf,ch,Tracks);
-  ARELEASE(mf,ch,Display);
-  ARELEASE(mf,ch,Children);
-}
-
-static void parseChapters(MatroskaFile *mf,ulonglong toplen) {
-  struct Chapter  *ch;
-
-  mf->seen.Chapters = 1;
-
-  FOREACH(mf,toplen)
-    case 0x45b9: // EditionEntry
-	ch = AGET(mf,Chapters);
-	memset(ch, 0, sizeof(*ch));
- 	FOREACH(mf,len)
-	  case 0x45bc: // EditionUID
-	    ch->UID = readUInt(mf,(unsigned)len);
-	    break;
-	  case 0x45bd: // EditionFlagHidden
-	    ch->Hidden = readUInt(mf,(unsigned)len)!=0;
-	    break;
-	  case 0x45db: // EditionFlagDefault
-	    ch->Default = readUInt(mf,(unsigned)len)!=0;
-	    break;
-	  case 0x45dd: // EditionFlagOrdered
-	    ch->Ordered = readUInt(mf,(unsigned)len)!=0;
-	    break;
-	  case 0xb6: // ChapterAtom
-	    parseChapter(mf,len,ch);
-	    break;
-	ENDFOR(mf);
-      break;
-  ENDFOR(mf);
-}
-
-static void parseTags(MatroskaFile *mf,ulonglong toplen) {
-  struct Tag  *tag;
-  struct Target *target;
-  struct SimpleTag *st;
-
-  mf->seen.Tags = 1;
-
-  FOREACH(mf,toplen)
-    case 0x7373: // Tag
-      tag = AGET(mf,Tags);
-      memset(tag,0,sizeof(*tag));
-
-      FOREACH(mf,len)
-	case 0x63c0: // Targets
-	  FOREACH(mf,len)
-	    case 0x63c5: // TrackUID
-	      target = ASGET(mf,tag,Targets);
-	      target->UID = readUInt(mf,(unsigned)len);
-	      target->Type = TARGET_TRACK;
-	      break;
-	    case 0x63c4: // ChapterUID
-	      target = ASGET(mf,tag,Targets);
-	      target->UID = readUInt(mf,(unsigned)len);
-	      target->Type = TARGET_CHAPTER;
-	      break;
-	    case 0x63c6: // AttachmentUID
-	      target = ASGET(mf,tag,Targets);
-	      target->UID = readUInt(mf,(unsigned)len);
-	      target->Type = TARGET_ATTACHMENT;
-	      break;
-	    case 0x63c9: // EditionUID
-	      target = ASGET(mf,tag,Targets);
-	      target->UID = readUInt(mf,(unsigned)len);
-	      target->Type = TARGET_EDITION;
-	      break;
-	  ENDFOR(mf);
-	  break;
-	case 0x67c8: // SimpleTag
-	  st = ASGET(mf,tag,SimpleTags);
-	  memset(st,0,sizeof(*st));
-
-	  FOREACH(mf,len)
-	    case 0x45a3: // TagName
-	      if (st->Name)
-		skipbytes(mf,len);
-	      else
-		STRGETM(mf,st->Name,len);
-	      break;
-	    case 0x4487: // TagString
-	      if (st->Value)
-		skipbytes(mf,len);
-	      else
-		STRGETM(mf,st->Value,len);
-	      break;
-	    case 0x447a: // TagLanguage
-	      readLangCC(mf, len, st->Language);
-	      break;
-	    case 0x4484: // TagDefault
-	      st->Default = readUInt(mf,(unsigned)len)!=0;
-	      break;
-	  ENDFOR(mf);
-
-	  if (!st->Name || !st->Value) {
-	    mf->cache->memfree(mf->cache,st->Name);
-	    mf->cache->memfree(mf->cache,st->Value);
-	    --tag->nSimpleTags;
-	  }
-	  break;
-      ENDFOR(mf);
-      break;
-  ENDFOR(mf);
-}
-
-static void parseContainer(MatroskaFile *mf) {
-  ulonglong len;
-  int	    id = readID(mf);
-  if (id==EOF)
-    errorjmp(mf,"Unexpected EOF in parseContainer");
-
-  len = readSize(mf);
-
-  switch (id) {
-    case 0x1549a966: // SegmentInfo
-      parseSegmentInfo(mf,len);
-      break;
-    case 0x1f43b675: // Cluster
-      parseFirstCluster(mf,len);
-      break;
-    case 0x1654ae6b: // Tracks
-      parseTracks(mf,len);
-      break;
-    case 0x1c53bb6b: // Cues
-      parseCues(mf,len);
-      break;
-    case 0x1941a469: // Attachments
-      parseAttachments(mf,len);
-      break;
-    case 0x1043a770: // Chapters
-      parseChapters(mf,len);
-      break;
-    case 0x1254c367: // Tags
-      parseTags(mf,len);
-      break;
-  }
-}
-
-static void parseContainerPos(MatroskaFile *mf,ulonglong pos) {
-  seek(mf,pos);
-  parseContainer(mf);
-}
-
-static void parsePointers(MatroskaFile *mf) {
-  jmp_buf		jb;
-
-  if (mf->pSegmentInfo && !mf->seen.SegmentInfo)
-    parseContainerPos(mf,mf->pSegmentInfo);
-  if (mf->pCluster && !mf->seen.Cluster)
-    parseContainerPos(mf,mf->pCluster);
-  if (mf->pTracks && !mf->seen.Tracks)
-    parseContainerPos(mf,mf->pTracks);
-
-  memcpy(&jb,&mf->jb,sizeof(jb));
-
-  if (setjmp(mf->jb)) 
-    mf->flags &= ~MPF_ERROR; // ignore errors
-  else {
-    if (mf->pCues && !mf->seen.Cues)
-	parseContainerPos(mf,mf->pCues);
-    if (mf->pAttachments && !mf->seen.Attachments)
-      parseContainerPos(mf,mf->pAttachments);
-    if (mf->pChapters && !mf->seen.Chapters)
-      parseContainerPos(mf,mf->pChapters);
-    if (mf->pTags && !mf->seen.Tags)
-      parseContainerPos(mf,mf->pTags);
-  }
-
-  memcpy(&mf->jb,&jb,sizeof(jb));
-}
-
-static void parseSegment(MatroskaFile *mf,ulonglong toplen) {
-  ulonglong   nextpos;
-  unsigned    nSeekHeads = 0, dontstop = 0;
-  jmp_buf     jb;
-
-  memcpy(&jb,&mf->jb,sizeof(jb));
-
-  if (setjmp(mf->jb))
-    mf->flags &= ~MPF_ERROR;
-  else {
-    // we want to read data until we find a seekhead or a trackinfo
-    FOREACH2(mf,toplen,0x1f43b675)
-      case 0x114d9b74: // SeekHead
-        if (mf->flags & MKVF_AVOID_SEEKS) {
-	  skipbytes(mf,len);
-	  break;
-        }
-
-        nextpos = filepos(mf) + len;
-        do {
-	  mf->pSeekHead = 0;
-	  parseSeekHead(mf,len);
-	  ++nSeekHeads;
-	  if (mf->pSeekHead) { // this is possibly a chained SeekHead
-	    seek(mf,mf->pSeekHead);
-	    id = readID(mf);
-	    if (id==EOF) // chained SeekHead points to EOF?
-	      break;
-	    if (id != 0x114d9b74) // chained SeekHead doesnt point to a SeekHead?
-	      break;
-	    len = readSize(mf);
-	  }
-        } while (mf->pSeekHead && nSeekHeads < 10);
-        seek(mf,nextpos); // resume reading segment
-        break;
-      case 0x1549a966: // SegmentInfo
-        mf->pSegmentInfo = cur;
-        parseSegmentInfo(mf,len);
-        break;
-      case 0x1f43b675: // Cluster
-        if (!mf->pCluster)
-	  mf->pCluster = cur;
-        if (mf->seen.Cluster) {
-          if (len != MAXU64)
-	    skipbytes(mf,len);
-        } else
-	  parseFirstCluster(mf,len);
-        break;
-      case 0x1654ae6b: // Tracks
-        mf->pTracks = cur;
-        parseTracks(mf,len);
-        break;
-      case 0x1c53bb6b: // Cues
-        mf->pCues = cur;
-        parseCues(mf,len);
-        break;
-      case 0x1941a469: // Attachments
-        mf->pAttachments = cur;
-        parseAttachments(mf,len);
-        break;
-      case 0x1043a770: // Chapters
-        mf->pChapters = cur;
-        parseChapters(mf,len);
-        break;
-      case 0x1254c367: // Tags
-        mf->pTags = cur;
-        parseTags(mf,len);
-        break;
-    ENDFOR1(mf);
-      // if we have pointers to all key elements
-      if (!dontstop && mf->pSegmentInfo && mf->pTracks && mf->pCluster)
-        break;
-    ENDFOR2();
-  }
-
-  memcpy(&mf->jb,&jb,sizeof(jb));
-
-  parsePointers(mf);
-}
-
-static void parseBlockAdditions(MatroskaFile *mf, ulonglong toplen, ulonglong timecode, unsigned track) {
-  ulonglong	add_id = 1, add_pos, add_len;
-  unsigned char	have_add;
-
-  FOREACH(mf, toplen)
-    case 0xa6: // BlockMore
-      have_add = 0;
-      FOREACH(mf, len)
-	case 0xee: // BlockAddId
-	  add_id = readUInt(mf, (unsigned)len);
-	  break;
-	case 0xa5: // BlockAddition
-	  add_pos = filepos(mf);
-	  add_len = len;
-	  skipbytes(mf, len);
-	  ++have_add;
-	  break;
-      ENDFOR(mf);
-      if (have_add == 1 && id > 0 && id < 255) {
-	struct QueueEntry *qe = QAlloc(mf);
-	qe->Start = qe->End = timecode;
-	qe->Position = add_pos;
-	qe->Length = (unsigned)add_len;
-	qe->flags = FRAME_UNKNOWN_START | FRAME_UNKNOWN_END |
-	  (((unsigned)add_id << FRAME_STREAM_SHIFT) & FRAME_STREAM_MASK);
-
-	QPut(&mf->Queues[track],qe);
-      }
-      break;
-  ENDFOR(mf);
-}
-
-static void parseBlockGroup(MatroskaFile *mf,ulonglong toplen,ulonglong timecode, int blockex) {
-  ulonglong	v;
-  ulonglong	duration = 0;
-  ulonglong	dpos;
-  struct QueueEntry *qe,*qf = NULL;
-  unsigned char	have_duration = 0, have_block = 0;
-  unsigned char	gap = 0;
-  unsigned char	lacing = 0;
-  unsigned char	ref = 0;
-  unsigned char	trackid;
-  unsigned	tracknum = 0;
-  int		c;
-  unsigned	nframes = 0,i;
-  unsigned	*sizes;
-  signed short	block_timecode;
-
-  if (blockex)
-    goto blockex;
-
-  FOREACH(mf,toplen)
-    case 0xfb: // ReferenceBlock
-      readSInt(mf,(unsigned)len);
-      ref = 1;
-      break;
-blockex:
-      cur = start = filepos(mf);
-      len = tmplen = toplen;
-    case 0xa1: // Block
-      have_block = 1;
-
-      dpos = filepos(mf);
-
-      v = readVLUInt(mf);
-      if (v>255)
-	errorjmp(mf,"Invalid track number in Block: %d",(int)v);
-      trackid = (unsigned char)v;
-
-      for (tracknum=0;tracknum<mf->nTracks;++tracknum)
-	if (mf->Tracks[tracknum]->Number == trackid) {
-	  if (mf->trackMask & (1<<tracknum)) // ignore this block
-	    break;
-	  goto found;
-	}
-
-      // bad trackid/unsupported track
-      skipbytes(mf,start + tmplen - filepos(mf)); // shortcut
-      return;
-found:
-
-      block_timecode = (signed short)readSInt(mf,2);
-
-      // recalculate this block's timecode to final timecode in ns
-      timecode = mul3(mf->Tracks[tracknum]->TimecodeScale,
-	(timecode - mf->firstTimecode + block_timecode) * mf->Seg.TimecodeScale);
-
-      c = readch(mf);
-      if (c==EOF)
-	errorjmp(mf,"Unexpected EOF while reading Block flags");
-
-      if (blockex)
-	ref = (unsigned char)!(c & 0x80);
-
-      gap = (unsigned char)(c & 0x1);
-      lacing = (unsigned char)((c >> 1) & 3);
-
-      if (lacing) {
-	c = readch(mf);
-	if (c == EOF)
-	  errorjmp(mf,"Unexpected EOF while reading lacing data");
-	nframes = c+1;
-      } else
-	nframes = 1;
-      sizes = alloca(nframes*sizeof(*sizes));
- 
-      switch (lacing) {
-	case 0: // No lacing
-	  sizes[0] = (unsigned)(len - filepos(mf) + dpos);
-	  break;
-	case 1: // Xiph lacing
-	  sizes[nframes-1] = 0;
-	  for (i=0;i<nframes-1;++i) {
-	    sizes[i] = 0;
-	    do {
-	      c = readch(mf);
-	      if (c==EOF)
-		errorjmp(mf,"Unexpected EOF while reading lacing data");
-	      sizes[i] += c;
-	    } while (c==255);
-	    sizes[nframes-1] += sizes[i];
-	  }
-	  sizes[nframes-1] = (unsigned)(len - filepos(mf) + dpos) - sizes[nframes-1];
-	  break;
-	case 3: // EBML lacing
-	  sizes[nframes-1] = 0;
-	  sizes[0] = (unsigned)readVLUInt(mf);
-	  for (i=1;i<nframes-1;++i) {
-	    sizes[i] = sizes[i-1] + (int)readVLSInt(mf);
-	    sizes[nframes-1] += sizes[i];
-	  }
-	  if (nframes>1)
-	    sizes[nframes-1] = (unsigned)(len - filepos(mf) + dpos) - sizes[0] - sizes[nframes-1];
-	  break;
-	case 2: // Fixed lacing
-	  sizes[0] = (unsigned)(len - filepos(mf) + dpos)/nframes;
-	  for (i=1;i<nframes;++i)
-	    sizes[i] = sizes[0];
-	  break;
-      }
-
-      v = filepos(mf);
-      qf = NULL;
-      for (i=0;i<nframes;++i) {
-	qe = QAlloc(mf);
-	if (!qf)
-	  qf = qe;
-
-	qe->Start = timecode;
-	qe->End = timecode;
-	qe->Position = v;
-	qe->Length = sizes[i];
-	qe->flags = FRAME_UNKNOWN_END | FRAME_KF;
-	if (i == nframes-1 && gap)
-	  qe->flags |= FRAME_GAP;
-	if (i > 0)
-	  qe->flags |= FRAME_UNKNOWN_START;
-
-	QPut(&mf->Queues[tracknum],qe);
-
-	v += sizes[i];
-      }
-
-      // we want to still load these bytes into cache
-      for (v = filepos(mf) & ~0x3fff; v < len + dpos; v += 0x4000)
-	mf->cache->read(mf->cache,v,NULL,0); // touch page
-
-      skipbytes(mf,len - filepos(mf) + dpos);
-
-      if (blockex)
-	goto out;
-      break;
-    case 0x9b: // BlockDuration
-      duration = readUInt(mf,(unsigned)len);
-      have_duration = 1;
-      break;
-    case 0x75a1: // BlockAdditions
-      if (nframes > 0) // have some frames
-	parseBlockAdditions(mf, len, timecode, tracknum);
-      else
-	skipbytes(mf, len);
-      break;
-  ENDFOR(mf);
-
-out:
-  if (!have_block)
-    errorjmp(mf,"Found a BlockGroup without Block");
-
-  if (nframes > 1) {
-    ulonglong defd = mf->Tracks[tracknum]->DefaultDuration;
-    v = qf->Start;
-
-    if (have_duration) {
-      duration = mul3(mf->Tracks[tracknum]->TimecodeScale,
-	duration * mf->Seg.TimecodeScale);
-
-      for (qe = qf; nframes > 1; --nframes, qe = qe->next) {
-	qe->Start = v;
-	v += defd;
-	duration -= defd;
-	qe->End = v;
-#if 0
-	qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
-#endif
-      }
-      qe->Start = v;
-      qe->End = v + duration;
-      qe->flags &= ~FRAME_UNKNOWN_END;
-    } else if (mf->Tracks[tracknum]->DefaultDuration) {
-      for (qe = qf; nframes > 0; --nframes, qe = qe->next) {
-	qe->Start = v;
-	v += defd;
-	qe->End = v;
-	qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
-      }
-    }
-  } else if (nframes == 1) {
-    if (have_duration) {
-      qf->End = qf->Start + mul3(mf->Tracks[tracknum]->TimecodeScale,
-	duration * mf->Seg.TimecodeScale);
-      qf->flags &= ~FRAME_UNKNOWN_END;
-    } else if (mf->Tracks[tracknum]->DefaultDuration) {
-      qf->End = qf->Start + mf->Tracks[tracknum]->DefaultDuration;
-      qf->flags &= ~FRAME_UNKNOWN_END;
-    }
-  }
-
-  if (ref)
-    while (qf) {
-      qf->flags &= ~FRAME_KF;
-      qf = qf->next;
-    }
-}
-
-static void ClearQueue(MatroskaFile *mf,struct Queue *q) {
-  struct QueueEntry *qe,*qn;
-
-  for (qe=q->head;qe;qe=qn) {
-    qn = qe->next;
-    qe->next = mf->QFreeList;
-    mf->QFreeList = qe;
-  }
-
-  q->head = NULL;
-  q->tail = NULL;
-}
-
-static void EmptyQueues(MatroskaFile *mf) {
-  unsigned	    i;
-
-  for (i=0;i<mf->nTracks;++i)
-    ClearQueue(mf,&mf->Queues[i]);
-}
-
-static int  readMoreBlocks(MatroskaFile *mf) {
-  ulonglong		toplen, cstop;
-  longlong		cp;
-  int			cid, ret = 0;
-  jmp_buf		jb;
-  volatile unsigned	retries = 0;
-
-  if (mf->readPosition >= mf->pSegmentTop)
-    return EOF;
-
-  memcpy(&jb,&mf->jb,sizeof(jb));
-
-  if (setjmp(mf->jb)) { // something evil happened here, try to resync
-    // always advance read position no matter what so
-    // we don't get caught in an endless loop
-    mf->readPosition = filepos(mf);
-
-    ret = EOF;
-
-    if (++retries > 3) // don't try too hard
-      goto ex;
-
-    for (;;) {
-      if (filepos(mf) >= mf->pSegmentTop)
-	goto ex;
-
-      cp = mf->cache->scan(mf->cache,filepos(mf),0x1f43b675); // cluster
-
-      if (cp < 0 || (ulonglong)cp >= mf->pSegmentTop)
-	goto ex;
-
-      seek(mf,cp);
-
-      cid = readID(mf);
-      if (cid == EOF)
-	goto ex;
-      if (cid == 0x1f43b675) {
-	toplen = readSizeUnspec(mf);
-	if (toplen < MAXCLUSTER || toplen == MAXU64) {
-	  // reset error flags
-	  mf->flags &= ~MPF_ERROR;
-	  ret = RBRESYNC;
-	  break;
-	}
-      }
-    }
-
-    mf->readPosition = cp;
-  }
-
-  cstop = mf->cache->getcachesize(mf->cache)>>1;
-  if (cstop > MAX_READAHEAD)
-    cstop = MAX_READAHEAD;
-  cstop += mf->readPosition;
-
-  seek(mf,mf->readPosition);
-
-  while (filepos(mf) < mf->pSegmentTop) {
-    cid = readID(mf);
-    if (cid == EOF) {
-      ret = EOF;
-      break;
-    }
-    toplen = cid == 0x1f43b675 ? readSizeUnspec(mf) : readSize(mf);
-
-    if (cid == 0x1f43b675) { // Cluster
-      unsigned char	have_timecode = 0;
-
-      FOREACH2(mf,toplen,0x1f43b675)
-        case 0x1f43b675:
-          RESTART();
-          break;
-	case 0xe7: // Timecode
-	  mf->tcCluster = readUInt(mf,(unsigned)len);
-	  have_timecode = 1;
-	  break;
-	case 0xa7: // Position
-	  readUInt(mf,(unsigned)len);
-	  break;
-	case 0xab: // PrevSize
-	  readUInt(mf,(unsigned)len);
-	  break;
-	case 0x5854: { // SilentTracks
-	  unsigned  stmask = 0, i, trk;
-	  FOREACH(mf, len)
-	    case 0x58d7: // SilentTrackNumber
-	      trk = (unsigned)readUInt(mf, (unsigned)len);
-	      for (i = 0; i < mf->nTracks; ++i)
-		if (mf->Tracks[i]->Number == trk) {
-		  stmask |= 1 << i;
-		  break;
-		}
-	      break;
-	  ENDFOR(mf);
-	  // TODO pass stmask to reading app
-	  break; }
-	case 0xa0: // BlockGroup
-	  if (!have_timecode)
-	    errorjmp(mf,"Found BlockGroup before cluster TimeCode");
-	  parseBlockGroup(mf,len,mf->tcCluster, 0);
-	  goto out;
-	case 0xa3: // BlockEx
-	  if (!have_timecode)
-	    errorjmp(mf,"Found BlockGroup before cluster TimeCode");
-	  parseBlockGroup(mf, len, mf->tcCluster, 1);
-	  goto out;
-      ENDFOR(mf);
-out:;
-    } else {
-      if (toplen > MAXFRAME)
-	errorjmp(mf,"Element in a cluster is too large around %llu, %X [%u]",filepos(mf),cid,(unsigned)toplen);
-      if (cid == 0xa0) // BlockGroup
-	parseBlockGroup(mf,toplen,mf->tcCluster, 0);
-      else if (cid == 0xa3) // BlockEx
-	parseBlockGroup(mf, toplen, mf->tcCluster, 1);
-      else
-	skipbytes(mf,toplen);
-    }
-
-    if ((mf->readPosition = filepos(mf)) > cstop)
-      break;
-  }
-
-  mf->readPosition = filepos(mf);
-
-ex:
-  memcpy(&mf->jb,&jb,sizeof(jb));
-
-  return ret;
-}
-
-// this is almost the same as readMoreBlocks, except it ensures
-// there are no partial frames queued, however empty queues are ok
-static int  fillQueues(MatroskaFile *mf,unsigned int mask) {
-  unsigned    i,j;
-  int	      ret = 0;
-
-  for (;;) {
-    j = 0;
-
-    for (i=0;i<mf->nTracks;++i)
-      if (mf->Queues[i].head && !(mask & (1<<i)))
-	++j;
-
-    if (j>0) // have at least some frames
-      return ret;
-
-    if ((ret = readMoreBlocks(mf)) < 0) {
-      j = 0;
-      for (i=0;i<mf->nTracks;++i)
-	if (mf->Queues[i].head && !(mask & (1<<i)))
-	  ++j;
-      if (j) // we adjusted some blocks
-	return 0;
-      return EOF;
-    }
-  }
-}
-
-static void reindex(MatroskaFile *mf) {
-  jmp_buf     jb;
-  ulonglong   pos = mf->pCluster;
-  ulonglong   step = 10*1024*1024;
-  ulonglong   size, tc, isize;
-  longlong    next_cluster;
-  int	      id, have_tc, bad;
-  struct Cue  *cue;
-
-  if (pos >= mf->pSegmentTop)
-    return;
-
-  if (pos + step * 10 > mf->pSegmentTop)
-    step = (mf->pSegmentTop - pos) / 10;
-  if (step == 0)
-    step = 1;
-
-  memcpy(&jb,&mf->jb,sizeof(jb));
-
-  // remove all cues
-  mf->nCues = 0;
-
-  bad = 0;
-
-  while (pos < mf->pSegmentTop) {
-    if (!mf->cache->progress(mf->cache,pos,mf->pSegmentTop))
-      break;
-
-    if (++bad > 50) {
-      pos += step;
-      bad = 0;
-      continue;
-    }
-
-    // find next cluster header
-    next_cluster = mf->cache->scan(mf->cache,pos,0x1f43b675); // cluster
-    if (next_cluster < 0 || (ulonglong)next_cluster >= mf->pSegmentTop)
-      break;
-
-    pos = next_cluster + 4; // prevent endless loops
-
-    if (setjmp(mf->jb)) // something evil happened while reindexing
-      continue;
-
-    seek(mf,next_cluster);
-
-    id = readID(mf);
-    if (id == EOF)
-      break;
-    if (id != 0x1f43b675) // shouldn't happen
-      continue;
-
-    size = readSizeUnspec(mf);
-    if (size == MAXU64)
-      break;
-
-    if (size >= MAXCLUSTER || size < 1024)
-      continue;
-
-    have_tc = 0;
-    size += filepos(mf);
-
-    while (filepos(mf) < (ulonglong)next_cluster + 1024) {
-      id = readID(mf);
-      if (id == EOF)
-	break;
-
-      isize = readVLUInt(mf);
-
-      if (id == 0xe7) { // cluster timecode
-	tc = readUInt(mf,(unsigned)isize);
-	have_tc = 1;
-	break;
-      }
-
-      skipbytes(mf,isize);
-    }
-
-    if (!have_tc)
-      continue;
-
-    seek(mf,size);
-    id = readID(mf);
-
-    if (id == EOF)
-      break;
-
-    if (id != 0x1f43b675) // cluster
-      continue;
-
-    // good cluster, remember it
-    cue = AGET(mf,Cues);
-    cue->Time = tc;
-    cue->Position = next_cluster - mf->pSegment;
-    cue->Block = 0;
-    cue->Track = 0;
-
-    // advance to the next point
-    pos = next_cluster + step;
-    if (pos < size)
-      pos = size;
-
-    bad = 0;
-  }
-
-  fixupCues(mf);
-
-  if (mf->nCues == 0) {
-    cue = AGET(mf,Cues);
-    cue->Time = mf->firstTimecode;
-    cue->Position = mf->pCluster - mf->pSegment;
-    cue->Block = 0;
-    cue->Track = 0;
-  }
-
-  mf->cache->progress(mf->cache,0,0);
-
-  memcpy(&mf->jb,&jb,sizeof(jb));
-}
-
-static void fixupChapter(ulonglong adj, struct Chapter *ch) {
-  unsigned i;
-
-  if (ch->Start != 0)
-    ch->Start -= adj;
-  if (ch->End != 0)
-    ch->End -= adj;
-
-  for (i=0;i<ch->nChildren;++i)
-    fixupChapter(adj,&ch->Children[i]);
-}
-
-static longlong	findLastTimecode(MatroskaFile *mf) {
-  ulonglong   nd = 0;
-  unsigned    n,vtrack;
-
-  if (mf->nTracks == 0)
-    return -1;
-
-  for (n=vtrack=0;n<mf->nTracks;++n)
-    if (mf->Tracks[n]->Type == TT_VIDEO) {
-      vtrack = n;
-      goto ok;
-    }
-
-  return -1;
-ok:
-
-  EmptyQueues(mf);
-
-  if (mf->nCues == 0) {
-    mf->readPosition = mf->pCluster + 13000000 > mf->pSegmentTop ? mf->pCluster : mf->pSegmentTop - 13000000;
-    mf->tcCluster = 0;
-  } else {
-    mf->readPosition = mf->Cues[mf->nCues - 1].Position + mf->pSegment;
-    mf->tcCluster = mf->Cues[mf->nCues - 1].Time / mf->Seg.TimecodeScale;
-  }
-  mf->trackMask = ~(1 << vtrack);
-
-  do
-    while (mf->Queues[vtrack].head)
-    {
-      ulonglong   tc = mf->Queues[vtrack].head->flags & FRAME_UNKNOWN_END ?
-			  mf->Queues[vtrack].head->Start : mf->Queues[vtrack].head->End;
-      if (nd < tc)
-	nd = tc;
-      QFree(mf,QGet(&mf->Queues[vtrack]));
-    }
-  while (fillQueues(mf,0) != EOF);
-
-  mf->trackMask = 0;
-
-  EmptyQueues(mf);
-
-  // there may have been an error, but at this point we will ignore it
-  if (mf->flags & MPF_ERROR) {
-    mf->flags &= ~MPF_ERROR;
-    if (nd == 0)
-      return -1;
-  }
-
-  return nd;
-}
-
-static void parseFile(MatroskaFile *mf) {
-  ulonglong len = filepos(mf), adjust;
-  unsigned  i;
-  int	    id = readID(mf);
-
-  if (id==EOF)
-    errorjmp(mf,"Unexpected EOF at start of file");
-
-  // files with multiple concatenated segments can have only
-  // one EBML prolog
-  if (len > 0 && id == 0x18538067)
-    goto segment;
-
-  if (id!=0x1a45dfa3)
-    errorjmp(mf,"First element in file is not EBML");
-
-  parseEBML(mf,readSize(mf));
-
-  // next we need to find the first segment
-  for (;;) {
-    id = readID(mf);
-    if (id==EOF)
-      errorjmp(mf,"No segments found in the file");
-segment:
-    len = readSizeUnspec(mf);
-    if (id == 0x18538067) // Segment
-      break;
-    if (len == MAXU64)
-      errorjmp(mf,"No segments found in the file");
-    skipbytes(mf,len);
-  }
-
-  // found it
-  mf->pSegment = filepos(mf);
-  if (len == MAXU64) {
-    mf->pSegmentTop = MAXU64;
-    if (mf->cache->getfilesize) {
-      longlong seglen = mf->cache->getfilesize(mf->cache);
-      if (seglen > 0)
-	mf->pSegmentTop = seglen;
-    }
-  } else
-    mf->pSegmentTop = mf->pSegment + len;
-  parseSegment(mf,len);
-
-  // check if we got all data
-  if (!mf->seen.SegmentInfo)
-    errorjmp(mf,"Couldn't find SegmentInfo");
-  if (!mf->seen.Cluster)
-    mf->pCluster = mf->pSegmentTop;
-
-  adjust = mf->firstTimecode * mf->Seg.TimecodeScale;
-
-  for (i=0;i<mf->nChapters;++i)
-    fixupChapter(adjust, &mf->Chapters[i]);
-
-  fixupCues(mf);
-
-  // release extra memory
-  ARELEASE(mf,mf,Tracks);
-
-  // initialize reader
-  mf->Queues = mf->cache->memalloc(mf->cache,mf->nTracks * sizeof(*mf->Queues));
-  if (mf->Queues == NULL)
-    errorjmp(mf, "Ouf of memory");
-  memset(mf->Queues, 0, mf->nTracks * sizeof(*mf->Queues));
-
-  // try to detect real duration
-  if (!(mf->flags & MKVF_AVOID_SEEKS)) {
-    longlong nd = findLastTimecode(mf);
-    if (nd > 0)
-      mf->Seg.Duration = nd;
-  }
-
-  // move to first frame
-  mf->readPosition = mf->pCluster;
-  mf->tcCluster = mf->firstTimecode;
-}
-
-static void DeleteChapter(MatroskaFile *mf,struct Chapter *ch) {
-  unsigned i,j;
-
-  for (i=0;i<ch->nDisplay;++i)
-    mf->cache->memfree(mf->cache,ch->Display[i].String);
-  mf->cache->memfree(mf->cache,ch->Display);
-  mf->cache->memfree(mf->cache,ch->Tracks);
-
-  for (i=0;i<ch->nProcess;++i) {
-    for (j=0;j<ch->Process[i].nCommands;++j)
-      mf->cache->memfree(mf->cache,ch->Process[i].Commands[j].Command);
-    mf->cache->memfree(mf->cache,ch->Process[i].Commands);
-    mf->cache->memfree(mf->cache,ch->Process[i].CodecPrivate);
-  }
-  mf->cache->memfree(mf->cache,ch->Process);
-
-  for (i=0;i<ch->nChildren;++i)
-    DeleteChapter(mf,&ch->Children[i]);
-  mf->cache->memfree(mf->cache,ch->Children);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// public interface
-MatroskaFile  *mkv_OpenEx(InputStream *io,
-			  ulonglong base,
-			  unsigned flags,
-			  char *err_msg,unsigned msgsize)
-{
-  MatroskaFile	*mf = io->memalloc(io,sizeof(*mf));
-  if (mf == NULL) {
-    mystrlcpy(err_msg,"Out of memory",msgsize);
-    return NULL;
-  }
-
-  memset(mf,0,sizeof(*mf));
-
-  mf->cache = io;
-  mf->flags = flags;
-  io->progress(io,0,0);
-
-  if (setjmp(mf->jb)==0) {
-    seek(mf,base);
-    parseFile(mf);
-  } else { // parser error
-    mystrlcpy(err_msg,mf->errmsg,msgsize);
-    mkv_Close(mf);
-    return NULL;
-  }
-
-  return mf;
-}
-
-MatroskaFile  *mkv_Open(InputStream *io,
-			char *err_msg,unsigned msgsize)
-{
-  return mkv_OpenEx(io,0,0,err_msg,msgsize);
-}
-
-void	      mkv_Close(MatroskaFile *mf) {
-  unsigned  i,j;
-
-  if (mf==NULL)
-    return;
-
-  for (i=0;i<mf->nTracks;++i)
-    mf->cache->memfree(mf->cache,mf->Tracks[i]);
-  mf->cache->memfree(mf->cache,mf->Tracks);
-
-  for (i=0;i<mf->nQBlocks;++i)
-    mf->cache->memfree(mf->cache,mf->QBlocks[i]);
-  mf->cache->memfree(mf->cache,mf->QBlocks);
-
-  mf->cache->memfree(mf->cache,mf->Queues);
-
-  mf->cache->memfree(mf->cache,mf->Seg.Title);
-  mf->cache->memfree(mf->cache,mf->Seg.MuxingApp);
-  mf->cache->memfree(mf->cache,mf->Seg.WritingApp);
-  mf->cache->memfree(mf->cache,mf->Seg.Filename);
-  mf->cache->memfree(mf->cache,mf->Seg.NextFilename);
-  mf->cache->memfree(mf->cache,mf->Seg.PrevFilename);
-
-  mf->cache->memfree(mf->cache,mf->Cues);
-
-  for (i=0;i<mf->nAttachments;++i) {
-    mf->cache->memfree(mf->cache,mf->Attachments[i].Description);
-    mf->cache->memfree(mf->cache,mf->Attachments[i].Name);
-    mf->cache->memfree(mf->cache,mf->Attachments[i].MimeType);
-  }
-  mf->cache->memfree(mf->cache,mf->Attachments);
-
-  for (i=0;i<mf->nChapters;++i)
-    DeleteChapter(mf,&mf->Chapters[i]);
-  mf->cache->memfree(mf->cache,mf->Chapters);
-
-  for (i=0;i<mf->nTags;++i) {
-    for (j=0;j<mf->Tags[i].nSimpleTags;++j) {
-      mf->cache->memfree(mf->cache,mf->Tags[i].SimpleTags[j].Name);
-      mf->cache->memfree(mf->cache,mf->Tags[i].SimpleTags[j].Value);
-    }
-    mf->cache->memfree(mf->cache,mf->Tags[i].Targets);
-    mf->cache->memfree(mf->cache,mf->Tags[i].SimpleTags);
-  }
-  mf->cache->memfree(mf->cache,mf->Tags);
-
-  mf->cache->memfree(mf->cache,mf);
-}
-
-const char    *mkv_GetLastError(MatroskaFile *mf) {
-  return mf->errmsg[0] ? mf->errmsg : NULL;
-}
-
-SegmentInfo   *mkv_GetFileInfo(MatroskaFile *mf) {
-  return &mf->Seg;
-}
-
-unsigned int  mkv_GetNumTracks(MatroskaFile *mf) {
-  return mf->nTracks;
-}
-
-TrackInfo     *mkv_GetTrackInfo(MatroskaFile *mf,unsigned track) {
-  if (track>mf->nTracks)
-    return NULL;
-
-  return mf->Tracks[track];
-}
-
-void	      mkv_GetAttachments(MatroskaFile *mf,Attachment **at,unsigned *count) {
-  *at = mf->Attachments;
-  *count = mf->nAttachments;
-}
-
-void	      mkv_GetChapters(MatroskaFile *mf,Chapter **ch,unsigned *count) {
-  *ch = mf->Chapters;
-  *count = mf->nChapters;
-}
-
-void	      mkv_GetTags(MatroskaFile *mf,Tag **tag,unsigned *count) {
-  *tag = mf->Tags;
-  *count = mf->nTags;
-}
-
-ulonglong     mkv_GetSegmentTop(MatroskaFile *mf) {
-  return mf->pSegmentTop;
-}
-
-#define	IS_DELTA(f) (!((f)->flags & FRAME_KF) || ((f)->flags & FRAME_UNKNOWN_START))
-
-void  mkv_Seek(MatroskaFile *mf,ulonglong timecode,unsigned flags) {
-  int		i,j,m,ret;
-  unsigned	n,z,mask;
-  ulonglong	m_kftime[MAX_TRACKS];
-  unsigned char	m_seendf[MAX_TRACKS];
-
-  if (mf->flags & MKVF_AVOID_SEEKS)
-    return;
-
-  if (timecode == 0) {
-    EmptyQueues(mf);
-    mf->readPosition = mf->pCluster;
-    mf->tcCluster = mf->firstTimecode;
-    mf->flags &= ~MPF_ERROR;
-
-    return;
-  }
-
-  if (mf->nCues==0)
-    reindex(mf);
-
-  if (mf->nCues==0)
-    return;
-
-  mf->flags &= ~MPF_ERROR;
-
-  i = 0;
-  j = mf->nCues - 1;
-
-  for (;;) {
-    if (i>j) {
-      j = j>=0 ? j : 0;
-
-      if (setjmp(mf->jb)!=0)
-	return;
-
-      mkv_SetTrackMask(mf,mf->trackMask);
-
-      if (flags & (MKVF_SEEK_TO_PREV_KEYFRAME | MKVF_SEEK_TO_PREV_KEYFRAME_STRICT)) {
-	// we do this in two stages
-	// a. find the last keyframes before the require position
-	// b. seek to them
-
-	// pass 1
-	for (;;) {
-	  for (n=0;n<mf->nTracks;++n) {
-	    m_kftime[n] = MAXU64;
-	    m_seendf[n] = 0;
-	  }
-
-	  EmptyQueues(mf);
-
-	  mf->readPosition = mf->Cues[j].Position + mf->pSegment;
-	  mf->tcCluster = mf->Cues[j].Time;
-
-	  for (;;) {
-	    if ((ret = fillQueues(mf,0)) < 0 || ret == RBRESYNC)
-	      return;
-
-	    // drain queues until we get to the required timecode
-	    for (n=0;n<mf->nTracks;++n) {
-	      if (mf->Queues[n].head && (mf->Queues[n].head->Start<timecode || (m_seendf[n] == 0 && m_kftime[n] == MAXU64))) {
-		if (IS_DELTA(mf->Queues[n].head))
-		  m_seendf[n] = 1;
-		else
-		  m_kftime[n] = mf->Queues[n].head->Start;
-	      }
-
-	      while (mf->Queues[n].head && mf->Queues[n].head->Start<timecode)
-	      {
-		if (IS_DELTA(mf->Queues[n].head))
-		  m_seendf[n] = 1;
-		else
-		  m_kftime[n] = mf->Queues[n].head->Start;
-		QFree(mf,QGet(&mf->Queues[n]));
-	      }
-
-              // We've drained the queue, so the frame at head is the next one past the requered point.
-              // In strict mode we are done, but when seeking is not strict we use the head frame
-              // if it's not an audio track (we accept preroll within a frame for audio), and the head frame
-              // is a keyframe
-              if (!(flags & MKVF_SEEK_TO_PREV_KEYFRAME_STRICT))
-	        if (mf->Queues[n].head && (mf->Tracks[n]->Type != TT_AUDIO || mf->Queues[n].head->Start<=timecode))
-		  if (!IS_DELTA(mf->Queues[n].head))
-		    m_kftime[n] = mf->Queues[n].head->Start;
-	    }
-
-	    for (n=0;n<mf->nTracks;++n)
-	      if (mf->Queues[n].head && mf->Queues[n].head->Start>=timecode)
-		goto found;
-	  }
-found:
-  
-	  for (n=0;n<mf->nTracks;++n)
-	    if (!(mf->trackMask & (1<<n)) && m_kftime[n]==MAXU64 &&
-		m_seendf[n] && j>0)
-	    {
-	      // we need to restart the search from prev cue
-	      --j;
-	      goto again;
-	    }
-
-	  break;
-again:;
-	}
-      } else
-	for (n=0;n<mf->nTracks;++n)
-	  m_kftime[n] = timecode;
-
-      // now seek to this timecode
-      EmptyQueues(mf);
-
-      mf->readPosition = mf->Cues[j].Position + mf->pSegment;
-      mf->tcCluster = mf->Cues[j].Time;
-
-      for (mask=0;;) {
-	if ((ret = fillQueues(mf,mask)) < 0 || ret == RBRESYNC)
-	  return;
-
-	// drain queues until we get to the required timecode
-	for (n=0;n<mf->nTracks;++n) {
-	  struct QueueEntry *qe;
-	  for (qe = mf->Queues[n].head;qe && qe->Start<m_kftime[n];qe = mf->Queues[n].head)
-	    QFree(mf,QGet(&mf->Queues[n]));
-	}
-
-	for (n=z=0;n<mf->nTracks;++n)
-	  if (m_kftime[n]==MAXU64 || (mf->Queues[n].head && mf->Queues[n].head->Start>=m_kftime[n])) {
-	    ++z;
-	    mask |= 1<<n;
-	  }
-
-	if (z==mf->nTracks)
-	  return;
-      }
-    }
-
-    m = (i+j)>>1;
-
-    if (timecode < mf->Cues[m].Time)
-      j = m-1;
-    else
-      i = m+1;
-  }
-}
-
-void  mkv_SkipToKeyframe(MatroskaFile *mf) {
-  unsigned  n,wait;
-  ulonglong ht;
-
-  if (setjmp(mf->jb)!=0)
-    return;
-
-  // remove delta frames from queues
-  do {
-    wait = 0;
-
-    if (fillQueues(mf,0)<0)
-      return;
-
-    for (n=0;n<mf->nTracks;++n)
-      if (mf->Queues[n].head && !(mf->Queues[n].head->flags & FRAME_KF)) {
-	++wait;
-	QFree(mf,QGet(&mf->Queues[n]));
-      }
-  } while (wait);
-
-  // find highest queued time
-  for (n=0,ht=0;n<mf->nTracks;++n)
-    if (mf->Queues[n].head && ht<mf->Queues[n].head->Start)
-      ht = mf->Queues[n].head->Start;
-
-  // ensure the time difference is less than 100ms
-  do {
-    wait = 0;
-
-    if (fillQueues(mf,0)<0)
-      return;
-
-    for (n=0;n<mf->nTracks;++n)
-      while (mf->Queues[n].head && mf->Queues[n].head->next &&
-	  (mf->Queues[n].head->next->flags & FRAME_KF) &&
-	  ht - mf->Queues[n].head->Start > 100000000)
-      {
-	++wait;
-	QFree(mf,QGet(&mf->Queues[n]));
-      }
-
-  } while (wait);
-}
-
-ulonglong mkv_GetLowestQTimecode(MatroskaFile *mf) {
-  unsigned  n,seen;
-  ulonglong t;
-
-  // find the lowest queued timecode
-  for (n=seen=0,t=0;n<mf->nTracks;++n)
-    if (mf->Queues[n].head && (!seen || t > mf->Queues[n].head->Start))
-      t = mf->Queues[n].head->Start, seen=1;
-
-  return seen ? t : (ulonglong)LL(-1);
-}
-
-int	      mkv_TruncFloat(MKFLOAT f) {
-#ifdef MATROSKA_INTEGER_ONLY
-  return (int)(f.v >> 32);
-#else
-  return (int)f;
-#endif
-}
-
-#define	FTRACK	0xffffffff
-
-void	      mkv_SetTrackMask(MatroskaFile *mf,unsigned int mask) {
-  unsigned int	  i;
-
-  if (mf->flags & MPF_ERROR)
-    return;
-
-  mf->trackMask = mask;
-
-  for (i=0;i<mf->nTracks;++i)
-    if (mask & (1<<i))
-      ClearQueue(mf,&mf->Queues[i]);
-}
-
-int	      mkv_ReadFrame(MatroskaFile *mf,
-			    unsigned int mask,unsigned int *track,
-			    ulonglong *StartTime,ulonglong *EndTime,
-			    ulonglong *FilePos,unsigned int *FrameSize,
-			    unsigned int *FrameFlags)
-{
-  unsigned int	    i,j;
-  struct QueueEntry *qe;
-
-  if (setjmp(mf->jb)!=0)
-    return -1;
-
-  do {
-    // extract required frame, use block with the lowest timecode
-    for (j=FTRACK,i=0;i<mf->nTracks;++i)
-      if (!(mask & (1<<i)) && mf->Queues[i].head) {
-	j = i;
-	++i;
-	break;
-      }
-
-    for (;i<mf->nTracks;++i)
-      if (!(mask & (1<<i)) && mf->Queues[i].head &&
-	  mf->Queues[j].head->Start > mf->Queues[i].head->Start)
-	j = i;
-
-    if (j != FTRACK) {
-      qe = QGet(&mf->Queues[j]);
-
-      *track = j;
-      *StartTime = qe->Start;
-      *EndTime = qe->End;
-      *FilePos = qe->Position;
-      *FrameSize = qe->Length;
-      *FrameFlags = qe->flags;
-
-      QFree(mf,qe);
-
-      return 0;
-    }
-
-    if (mf->flags & MPF_ERROR)
-      return -1;
-
-  } while (fillQueues(mf,mask)>=0);
-
-  return EOF;
-}
-
-#ifdef MATROSKA_COMPRESSION_SUPPORT
-/*************************************************************************
- * Compressed streams support
- ************************************************************************/
-struct CompressedStream {
-  MatroskaFile	  *mf;
-  z_stream	  zs;
-
-  /* current compressed frame */
-  ulonglong	  frame_pos;
-  unsigned	  frame_size;
-  char		  frame_buffer[2048];
-
-  /* decoded data buffer */
-  char		  decoded_buffer[2048];
-  unsigned	  decoded_ptr;
-  unsigned	  decoded_size;
-
-  /* error handling */
-  char		  errmsg[128];
-};
-
-CompressedStream  *cs_Create(/* in */	MatroskaFile *mf,
-			     /* in */	unsigned tracknum,
-			     /* out */	char *errormsg,
-			     /* in */	unsigned msgsize)
-{
-  CompressedStream  *cs;
-  TrackInfo	    *ti;
-  int		    code;
-
-  ti = mkv_GetTrackInfo(mf, tracknum);
-  if (ti == NULL) {
-    mystrlcpy(errormsg, "No such track.", msgsize);
-    return NULL;
-  }
-
-  if (!ti->CompEnabled) {
-    mystrlcpy(errormsg, "Track is not compressed.", msgsize);
-    return NULL;
-  }
-
-  if (ti->CompMethod != COMP_ZLIB) {
-    mystrlcpy(errormsg, "Unsupported compression method.", msgsize);
-    return NULL;
-  }
-
-  cs = mf->cache->memalloc(mf->cache,sizeof(*cs));
-  if (cs == NULL) {
-    mystrlcpy(errormsg, "Ouf of memory.", msgsize);
-    return NULL;
-  }
-
-  memset(&cs->zs,0,sizeof(cs->zs));
-  code = inflateInit(&cs->zs);
-  if (code != Z_OK) {
-    mystrlcpy(errormsg, "ZLib error.", msgsize);
-    mf->cache->memfree(mf->cache,cs);
-    return NULL;
-  }
-
-  cs->frame_size = 0;
-  cs->decoded_ptr = cs->decoded_size = 0;
-  cs->mf = mf;
-
-  return cs;
-}
-
-void		  cs_Destroy(/* in */ CompressedStream *cs) {
-  if (cs == NULL)
-    return;
-
-  inflateEnd(&cs->zs);
-  cs->mf->cache->memfree(cs->mf->cache,cs);
-}
-
-/* advance to the next frame in matroska stream, you need to pass values returned
- * by mkv_ReadFrame */
-void		  cs_NextFrame(/* in */ CompressedStream *cs,
-			       /* in */ ulonglong pos,
-			       /* in */ unsigned size)
-{
-  cs->zs.avail_in = 0;
-  inflateReset(&cs->zs);
-  cs->frame_pos = pos;
-  cs->frame_size = size;
-  cs->decoded_ptr = cs->decoded_size = 0;
-}
-
-/* read and decode more data from current frame, return number of bytes decoded,
- * 0 on end of frame, or -1 on error */
-int		  cs_ReadData(CompressedStream *cs,char *buffer,unsigned bufsize)
-{
-  char	    *cp = buffer;
-  unsigned  rd = 0;
-  unsigned  todo;
-  int	    code;
-  
-  do {
-    /* try to copy data from decoded buffer */
-    if (cs->decoded_ptr < cs->decoded_size) {
-      todo = cs->decoded_size - cs->decoded_ptr;;
-      if (todo > bufsize - rd)
-	todo = bufsize - rd;
-
-      memcpy(cp, cs->decoded_buffer + cs->decoded_ptr, todo);
-
-      rd += todo;
-      cp += todo;
-      cs->decoded_ptr += todo;
-    } else {
-      /* setup output buffer */
-      cs->zs.next_out = (Bytef *)cs->decoded_buffer;
-      cs->zs.avail_out = sizeof(cs->decoded_buffer);
-
-      /* try to read more data */
-      if (cs->zs.avail_in == 0 && cs->frame_size > 0) {
-	todo = cs->frame_size;
-	if (todo > sizeof(cs->frame_buffer))
-	  todo = sizeof(cs->frame_buffer);
-
-	if (cs->mf->cache->read(cs->mf->cache, cs->frame_pos, cs->frame_buffer, todo) != (int)todo) {
-	  mystrlcpy(cs->errmsg, "File read failed", sizeof(cs->errmsg));
-	  return -1;
-	}
-
-	cs->zs.next_in = (Bytef *)cs->frame_buffer;
-	cs->zs.avail_in = todo;
-
-	cs->frame_pos += todo;
-	cs->frame_size -= todo;
-      }
-
-      /* try to decode more data */
-      code = inflate(&cs->zs,Z_NO_FLUSH);
-      if (code != Z_OK && code != Z_STREAM_END) {
-	mystrlcpy(cs->errmsg, "ZLib error.", sizeof(cs->errmsg));
-	return -1;
-      }
-
-      /* handle decoded data */
-      if (cs->zs.avail_out == sizeof(cs->decoded_buffer)) /* EOF */
-	break;
-
-      cs->decoded_ptr = 0;
-      cs->decoded_size = sizeof(cs->decoded_buffer) - cs->zs.avail_out;
-    }
-  } while (rd < bufsize);
-
-  return rd;
-}
-
-/* return error message for the last error */
-const char	  *cs_GetLastError(CompressedStream *cs)
-{
-  if (!cs->errmsg[0])
-    return NULL;
-  return cs->errmsg;
-}
-#endif
diff --git a/aegisub/libffms/src/core/matroskaparser.h b/aegisub/libffms/src/core/matroskaparser.h
deleted file mode 100644
index b3e1f75ad..000000000
--- a/aegisub/libffms/src/core/matroskaparser.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Mike Matsnev.  All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. 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.
- * 3. Absolutely no warranty of function or purpose is made by the author
- *    Mike Matsnev.
- *
- * 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.
- * 
- * $Id: MatroskaParser.h,v 1.22 2008/04/29 21:03:09 mike Exp $
- * 
- */
-
-#ifndef MATROSKA_PARSER_H
-#define	MATROSKA_PARSER_H
-
-/* Random notes:
- *
- * The parser does not process frame data in any way and does not read it into
- * the queue. The app should read it via mkv_ReadData if it is interested.
- *
- * The code here is 64-bit clean and was tested on FreeBSD/sparc 64-bit big endian
- * system
- */
-
-#ifdef MPDLLBUILD
-#define	X __declspec(dllexport)
-#else
-#ifdef MPDLL
-#define X __declspec(dllimport)
-#pragma comment(lib,"MatroskaParser")
-#else
-#define X
-#endif
-#endif
-
-#define MATROSKA_COMPRESSION_SUPPORT
-#define	MATROSKA_INTEGER_ONLY
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* 64-bit integers */
-#ifdef _WIN32_WCE
-typedef signed __int64	    longlong;
-typedef unsigned __int64    ulonglong;
-#else
-typedef signed long long    longlong;
-typedef unsigned long long  ulonglong;
-#endif
-
-/* MKFLOATing point */
-#ifdef MATROSKA_INTEGER_ONLY
-typedef struct {
-  longlong	v;
-} MKFLOAT;
-#else
-typedef	double	MKFLOAT;
-#endif
-
-/* generic I/O */
-struct InputStream {
-  /* read bytes from stream */
-  int	      (*read)(struct InputStream *cc,ulonglong pos,void *buffer,int count);
-  /* scan for a four byte signature, bytes must be nonzero */
-  longlong    (*scan)(struct InputStream *cc,ulonglong start,unsigned signature);
-  /* get cache size, this is used to cap readahead */
-  unsigned    (*getcachesize)(struct InputStream *cc);
-  /* fetch last error message */
-  const char *(*geterror)(struct InputStream *cc);
-  /* memory allocation */
-  void	      *(*memalloc)(struct InputStream *cc,size_t size);
-  void	      *(*memrealloc)(struct InputStream *cc,void *mem,size_t newsize);
-  void	      (*memfree)(struct InputStream *cc,void *mem);
-  /* zero return causes parser to abort open */
-  int	      (*progress)(struct InputStream *cc,ulonglong cur,ulonglong max);
-  /* get file size, optional, can be NULL or return -1 if filesize is unknown */
-  longlong    (*getfilesize)(struct InputStream *cc);
-};
-
-typedef struct InputStream InputStream;
-
-/* matroska file */
-struct MatroskaFile; /* opaque */
-
-typedef struct MatroskaFile MatroskaFile;
-
-#define	COMP_ZLIB   0
-#define	COMP_BZIP   1
-#define	COMP_LZO1X  2
-#define	COMP_PREPEND 3
-
-#define	TT_VIDEO    1
-#define	TT_AUDIO    2
-#define	TT_SUB	    17
-
-struct TrackInfo {
-  unsigned char	  Number;
-  unsigned char	  Type;
-  unsigned char	  TrackOverlay;
-  ulonglong	  UID;
-  ulonglong	  MinCache;
-  ulonglong	  MaxCache;
-  ulonglong	  DefaultDuration;
-  MKFLOAT	  TimecodeScale;
-  void		  *CodecPrivate;
-  unsigned	  CodecPrivateSize;
-  unsigned	  CompMethod;
-  void		  *CompMethodPrivate;
-  unsigned	  CompMethodPrivateSize;
-  unsigned	  MaxBlockAdditionID;
-
-  unsigned int  Enabled:1;
-  unsigned int  Default:1;
-  unsigned int  Lacing:1;
-  unsigned int  DecodeAll:1;
-  unsigned int  CompEnabled:1;
-
-  union {
-    struct {
-      unsigned char   StereoMode;
-      unsigned char   DisplayUnit;
-      unsigned char   AspectRatioType;
-      unsigned int    PixelWidth;
-      unsigned int    PixelHeight;
-      unsigned int    DisplayWidth;
-      unsigned int    DisplayHeight;
-      unsigned int    CropL, CropT, CropR, CropB;
-      unsigned int    ColourSpace;
-      MKFLOAT	      GammaValue;
-
-      unsigned int  Interlaced:1;
-    } Video;
-    struct {
-      MKFLOAT	      SamplingFreq;
-      MKFLOAT	      OutputSamplingFreq;
-      unsigned char   Channels;
-      unsigned char   BitDepth;
-    } Audio;
-  } AV;
-
-  /* various strings */
-  char			*Name;
-  char			Language[4];
-  char			*CodecID;
-};
-
-typedef struct TrackInfo  TrackInfo;
-
-struct SegmentInfo {
-  char			UID[16];
-  char			PrevUID[16];
-  char			NextUID[16];
-  char			*Filename;
-  char			*PrevFilename;
-  char			*NextFilename;
-  char			*Title;
-  char			*MuxingApp;
-  char			*WritingApp;
-  ulonglong		TimecodeScale;
-  ulonglong		Duration;
-  longlong		DateUTC;
-  char			DateUTCValid;
-};
-
-typedef struct SegmentInfo SegmentInfo;
-
-struct Attachment {
-  ulonglong		Position;
-  ulonglong		Length;
-  ulonglong		UID;
-  char			*Name;
-  char			*Description;
-  char			*MimeType;
-};
-
-typedef struct Attachment Attachment;
-
-struct ChapterDisplay {
-  char			*String;
-  char			Language[4];
-  char			Country[4];
-};
-
-struct ChapterCommand {
-  unsigned		Time;
-  unsigned		CommandLength;
-  void			*Command;
-};
-
-struct ChapterProcess {
-  unsigned		CodecID;
-  unsigned		CodecPrivateLength;
-  void			*CodecPrivate;
-  unsigned		nCommands,nCommandsSize;
-  struct ChapterCommand	*Commands;
-};
-
-struct Chapter {
-  ulonglong		UID;
-  ulonglong		Start;
-  ulonglong		End;
-
-  unsigned		nTracks,nTracksSize;
-  ulonglong		*Tracks;
-  unsigned		nDisplay,nDisplaySize;
-  struct ChapterDisplay	*Display;
-  unsigned		nChildren,nChildrenSize;
-  struct Chapter	*Children;
-  unsigned		nProcess,nProcessSize;
-  struct ChapterProcess	*Process;
-
-  char			SegmentUID[16];
-
-  unsigned int	Hidden:1;
-  unsigned int	Enabled:1;
-
-  // Editions
-  unsigned int	Default:1;
-  unsigned int	Ordered:1;
-};
-
-typedef struct Chapter	Chapter;
-
-#define	TARGET_TRACK	  0
-#define	TARGET_CHAPTER	  1
-#define	TARGET_ATTACHMENT 2
-#define	TARGET_EDITION	  3
-struct Target {
-  ulonglong	    UID;
-  unsigned	    Type;
-};
-
-struct SimpleTag {
-  char		    *Name;
-  char		    *Value;
-  char		    Language[4];
-  unsigned	    Default:1;
-};
-
-struct Tag {
-  unsigned	    nTargets,nTargetsSize;
-  struct Target	    *Targets;
-
-  unsigned	    nSimpleTags,nSimpleTagsSize;
-  struct SimpleTag  *SimpleTags;
-};
-
-typedef struct Tag  Tag;
-
-/* Open a matroska file
- * io pointer is recorded inside MatroskaFile
- */
-X MatroskaFile  *mkv_Open(/* in */ InputStream *io,
-			/* out */ char *err_msg,
-			/* in */  unsigned msgsize);
-
-#define	MKVF_AVOID_SEEKS    1 /* use sequential reading only */
-
-X MatroskaFile  *mkv_OpenEx(/* in */  InputStream *io,
-			  /* in */  ulonglong base,
-			  /* in */  unsigned flags,
-			  /* out */ char *err_msg,
-			  /* in */  unsigned msgsize);
-
-/* Close and deallocate mf
- * NULL pointer is ok and is simply ignored
- */
-X void		mkv_Close(/* in */ MatroskaFile *mf);
-
-/* Fetch the error message of the last failed operation */
-X const char    *mkv_GetLastError(/* in */ MatroskaFile *mf);
-
-/* Get file information */
-X SegmentInfo   *mkv_GetFileInfo(/* in */ MatroskaFile *mf);
-
-/* Get track information */
-X unsigned int  mkv_GetNumTracks(/* in */ MatroskaFile *mf);
-X TrackInfo     *mkv_GetTrackInfo(/* in */ MatroskaFile *mf,/* in */ unsigned track);
-
-/* chapters, tags and attachments */
-X void	      mkv_GetAttachments(/* in */   MatroskaFile *mf,
-				 /* out */  Attachment **at,
-				 /* out */  unsigned *count);
-X void	      mkv_GetChapters(/* in */	MatroskaFile *mf,
-			      /* out */	Chapter **ch,
-			      /* out */ unsigned *count);
-X void	      mkv_GetTags(/* in */  MatroskaFile *mf,
-			  /* out */ Tag **tag,
-			  /* out */ unsigned *count);
-
-X ulonglong   mkv_GetSegmentTop(MatroskaFile *mf);
-
-/* Seek to specified timecode,
- * if timecode is past end of file,
- * all tracks are set to return EOF
- * on next read
- */
-#define	MKVF_SEEK_TO_PREV_KEYFRAME          1
-#define	MKVF_SEEK_TO_PREV_KEYFRAME_STRICT   2
-
-X void	      mkv_Seek(/* in */ MatroskaFile *mf,
-		       /* in */	ulonglong timecode /* in ns */,
-		       /* in */ unsigned flags);
-
-X void	      mkv_SkipToKeyframe(MatroskaFile *mf);
-
-X ulonglong   mkv_GetLowestQTimecode(MatroskaFile *mf);
-
-X int	      mkv_TruncFloat(MKFLOAT f);
-
-/*************************************************************************
- * reading data, pull model
- */
-
-/* frame flags */
-#define	FRAME_UNKNOWN_START   0x00000001
-#define	FRAME_UNKNOWN_END     0x00000002
-#define	FRAME_KF	      0x00000004
-#define	FRAME_GAP	      0x00800000
-#define	FRAME_STREAM_MASK     0xff000000
-#define	FRAME_STREAM_SHIFT    24
-
-/* This sets the masking flags for the parser,
- *  masked tracks [with 1s in their bit positions]
- *  will be ignored when reading file data.
- * This call discards all parsed and queued frames
- */
-X void	      mkv_SetTrackMask(/* in */ MatroskaFile *mf,/* in */ unsigned int mask);
-
-/* Read one frame from the queue.
- * mask specifies what tracks to ignore.
- * Returns -1 if there are no more frames in the specified
- * set of tracks, 0 on success
- */
-X int	      mkv_ReadFrame(/* in */  MatroskaFile *mf,
-			    /* in */  unsigned int mask,
-			    /* out */ unsigned int *track,
-			    /* out */ ulonglong *StartTime /* in ns */,
-			    /* out */ ulonglong *EndTime /* in ns */,
-			    /* out */ ulonglong *FilePos /* in bytes from start of file */,
-			    /* out */ unsigned int *FrameSize /* in bytes */,
-			    /* out */ unsigned int *FrameFlags);
-
-#ifdef MATROSKA_COMPRESSION_SUPPORT
-/* Compressed streams support */
-struct CompressedStream;
-
-typedef struct CompressedStream CompressedStream;
-
-X CompressedStream  *cs_Create(/* in */	MatroskaFile *mf,
-			     /* in */	unsigned tracknum,
-			     /* out */	char *errormsg,
-			     /* in */	unsigned msgsize);
-X void		  cs_Destroy(/* in */ CompressedStream *cs);
-
-/* advance to the next frame in matroska stream, you need to pass values returned
- * by mkv_ReadFrame */
-X void		  cs_NextFrame(/* in */ CompressedStream *cs,
-			       /* in */ ulonglong pos,
-			       /* in */ unsigned size);
-
-/* read and decode more data from current frame, return number of bytes decoded,
- * 0 on end of frame, or -1 on error */
-X int		  cs_ReadData(CompressedStream *cs,char *buffer,unsigned bufsize);
-
-/* return error message for the last error */
-X const char	  *cs_GetLastError(CompressedStream *cs);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#undef X
-
-#endif
diff --git a/aegisub/libffms/src/core/matroskavideo.cpp b/aegisub/libffms/src/core/matroskavideo.cpp
deleted file mode 100644
index d2a7ddc07..000000000
--- a/aegisub/libffms/src/core/matroskavideo.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include "videosource.h"
-
-
-
-void FFMatroskaVideo::Free(bool CloseCodec) {
-	if (TCC)
-		delete TCC;
-	if (MC.ST.fp) {
-		mkv_Close(MF);
-	}
-	if (CloseCodec)
-		avcodec_close(CodecContext);
-	av_freep(&CodecContext);
-}
-
-FFMatroskaVideo::FFMatroskaVideo(const char *SourceFile, int Track,
-	FFMS_Index *Index, int Threads)
-	: Res(FFSourceResources<FFMS_VideoSource>(this)), FFMS_VideoSource(SourceFile, Index, Track) {
-
-	AVCodec *Codec = NULL;
-	CodecContext = NULL;
-	TrackInfo *TI = NULL;
-	TCC = NULL;
-	PacketNumber = 0;
-	VideoTrack = Track;
-	Frames = (*Index)[VideoTrack];
-
-	MC.ST.fp = ffms_fopen(SourceFile, "rb");
-	if (MC.ST.fp == NULL) {
-		std::ostringstream buf;
-		buf << "Can't open '" << SourceFile << "': " << strerror(errno);
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, buf.str());
-	}
-
-	setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE);
-
-	MF = mkv_OpenEx(&MC.ST.base, 0, 0, ErrorMessage, sizeof(ErrorMessage));
-	if (MF == NULL) {
-		std::ostringstream buf;
-		buf << "Can't parse Matroska file: " << ErrorMessage;
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, buf.str());
-	}
-
-	TI = mkv_GetTrackInfo(MF, VideoTrack);
-
-	if (TI->CompEnabled)
-		TCC = new TrackCompressionContext(MF, TI, VideoTrack);
-
-	CodecContext = avcodec_alloc_context();
-	if (avcodec_thread_init(CodecContext, Threads))
-		CodecContext->thread_count = 1;
-
-	Codec = avcodec_find_decoder(MatroskaToFFCodecID(TI->CodecID, TI->CodecPrivate));
-	if (Codec == NULL)
-		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
-			"Video codec not found");
-
-	InitializeCodecContextFromMatroskaTrackInfo(TI, CodecContext);
-
-	if (avcodec_open(CodecContext, Codec) < 0)
-		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
-			"Could not open video codec");
-
-	Res.CloseCodec(true);
-
-	// Always try to decode a frame to make sure all required parameters are known
-	DecodeNextFrame();
-
-	VP.FPSDenominator = 1;
-	VP.FPSNumerator = 30;
-	VP.RFFDenominator = CodecContext->time_base.num;
-	VP.RFFNumerator = CodecContext->time_base.den;
-	if (CodecContext->codec_id == CODEC_ID_H264) {
-		if (VP.RFFNumerator & 1)
-			VP.RFFDenominator *= 2;
-		else
-			VP.RFFNumerator /= 2;
-	}
-	VP.NumFrames = Frames.size();
-	VP.TopFieldFirst = DecodeFrame->top_field_first;
-#ifdef FFMS_HAVE_FFMPEG_COLORSPACE_INFO
-	VP.ColorSpace = CodecContext->colorspace;
-	VP.ColorRange = CodecContext->color_range;
-#else
-	VP.ColorSpace = 0;
-	VP.ColorRange = 0;
-#endif
-	// these pixfmt's are deprecated but still used
-	if (
-		CodecContext->pix_fmt == PIX_FMT_YUVJ420P 
-		|| CodecContext->pix_fmt == PIX_FMT_YUVJ422P
-		|| CodecContext->pix_fmt == PIX_FMT_YUVJ444P
-	)
-		VP.ColorRange = AVCOL_RANGE_JPEG;
-
-	VP.FirstTime = ((Frames.front().PTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
-	VP.LastTime = ((Frames.back().PTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
-
-	if (CodecContext->width <= 0 || CodecContext->height <= 0)
-		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
-			"Codec returned zero size video");
-
-	// Calculate the average framerate
-	if (Frames.size() >= 2) {
-		double PTSDiff = (double)(Frames.back().PTS - Frames.front().PTS);
-		VP.FPSDenominator = (unsigned int)(PTSDiff * mkv_TruncFloat(TI->TimecodeScale) / (double)1000 / (double)(VP.NumFrames - 1) + 0.5);
-		VP.FPSNumerator = 1000000; 
-	}
-
-	// attempt to correct framerate to the proper NTSC fraction, if applicable
-	CorrectNTSCRationalFramerate(&VP.FPSNumerator, &VP.FPSDenominator);
-	// correct the timebase, if necessary
-	CorrectTimebase(&VP, &Frames.TB);
-
-	// Output the already decoded frame so it isn't wasted
-	OutputFrame(DecodeFrame);
-
-	// Set AR variables
-	VP.SARNum = TI->AV.Video.DisplayWidth * TI->AV.Video.PixelHeight;
-	VP.SARDen = TI->AV.Video.DisplayHeight * TI->AV.Video.PixelWidth;
-
-	// Set crop variables
-	VP.CropLeft = TI->AV.Video.CropL;
-	VP.CropRight = TI->AV.Video.CropR;
-	VP.CropTop = TI->AV.Video.CropT;
-	VP.CropBottom = TI->AV.Video.CropB;
-}
-
-void FFMatroskaVideo::DecodeNextFrame() {
-	int FrameFinished = 0;
-	AVPacket Packet;
-	InitNullPacket(Packet);
-
-	unsigned int FrameSize;
-
-	if (InitialDecode == -1) {
-		if (DelayCounter > CodecContext->has_b_frames) {
-			DelayCounter--;
-			goto Done;
-		} else {
-			InitialDecode = 0;
-		}
-	}
-	
-	while (PacketNumber < Frames.size()) {
-		// The additional indirection is because the packets are stored in
-		// presentation order and not decoding order, this is unnoticable
-		// in the other sources where less is done manually
-		const TFrameInfo &FI = Frames[Frames[PacketNumber].OriginalPos];
-		FrameSize = FI.FrameSize;
-		ReadFrame(FI.FilePos, FrameSize, TCC, MC);
-
-		Packet.data = MC.Buffer;
-		Packet.size = (TCC && TCC->CompressionMethod == COMP_PREPEND) ? FrameSize + TCC->CompressedPrivateDataSize : FrameSize;
-		if (FI.KeyFrame)
-			Packet.flags = AV_PKT_FLAG_KEY;
-		else
-			Packet.flags = 0;
-
-		PacketNumber++;
-
-		avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &Packet);
-
-		if (!FrameFinished)
-			DelayCounter++;
-		if (DelayCounter > CodecContext->has_b_frames && !InitialDecode)
-			goto Done;
-
-		if (FrameFinished)
-			goto Done;
-	}
-
-	// Flush the last frames
-	if (CodecContext->has_b_frames) {
-		AVPacket NullPacket;
-		InitNullPacket(NullPacket);
-		avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &NullPacket);
-	}
-
-	if (!FrameFinished)
-		goto Error;
-
-Error:
-Done:
-	if (InitialDecode == 1) InitialDecode = -1;
-}
-
-FFMS_Frame *FFMatroskaVideo::GetFrame(int n) {
-	GetFrameCheck(n);
-
-	if (LastFrameNum == n)
-		return &LocalFrame;
-
-	int ClosestKF = Frames.FindClosestVideoKeyFrame(n);
-	if (CurrentFrame > n || ClosestKF > CurrentFrame + 10) {
-		DelayCounter = 0;
-		InitialDecode = 1;
-		PacketNumber = ClosestKF;
-		CurrentFrame = ClosestKF;
-		avcodec_flush_buffers(CodecContext);
-	}
-
-	do {
-		if (CurrentFrame+CodecContext->has_b_frames >= n)
-			CodecContext->skip_frame = AVDISCARD_DEFAULT;
-		else
-			CodecContext->skip_frame = AVDISCARD_NONREF;
-		DecodeNextFrame();
-		CurrentFrame++;
-	} while (CurrentFrame <= n);
-
-	LastFrameNum = n;
-	return OutputFrame(DecodeFrame);
-}
diff --git a/aegisub/libffms/src/core/stdiostream.c b/aegisub/libffms/src/core/stdiostream.c
deleted file mode 100644
index 9fdde8b15..000000000
--- a/aegisub/libffms/src/core/stdiostream.c
+++ /dev/null
@@ -1,116 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include "stdiostream.h"
-#include "ffmscompat.h"
-#include <errno.h>
-
-/* StdIoStream methods */
-
-/* read count bytes into buffer starting at file position pos
- * return the number of bytes read, -1 on error or 0 on EOF
- */
-int StdIoRead(StdIoStream *st, ulonglong pos, void *buffer, int count) {
-  size_t  rd;
-  if (fseeko(st->fp, pos, SEEK_SET)) {
-    st->error = errno;
-    return -1;
-  }
-  rd = fread(buffer, 1, count, st->fp);
-  if (rd == 0) {
-    if (feof(st->fp))
-      return 0;
-    st->error = errno;
-    return -1;
-  }
-  return rd;
-}
-
-/* scan for a signature sig(big-endian) starting at file position pos
- * return position of the first byte of signature or -1 if error/not found
- */
-longlong StdIoScan(StdIoStream *st, ulonglong start, unsigned signature) {
-  int	      c;
-  unsigned    cmp = 0;
-  FILE	      *fp = st->fp;
-
-  if (fseeko(fp, start, SEEK_SET))
-    return -1;
-
-  while ((c = getc(fp)) != EOF) {
-    cmp = ((cmp << 8) | c) & 0xffffffff;
-    if (cmp == signature)
-      return ftello(fp) - 4;
-  }
-
-  return -1;
-}
-
-/* return cache size, this is used to limit readahead */
-unsigned StdIoGetCacheSize(StdIoStream *st) {
-  return CACHESIZE;
-}
-
-/* return last error message */
-const char *StdIoGetLastError(StdIoStream *st) {
-  return strerror(st->error);
-}
-
-/* memory allocation, this is done via stdlib */
-void *StdIoMalloc(StdIoStream *st, size_t size) {
-  return malloc(size);
-}
-
-void *StdIoRealloc(StdIoStream *st, void *mem, size_t size) {
-  return realloc(mem,size);
-}
-
-void StdIoFree(StdIoStream *st, void *mem) {
-  free(mem);
-}
-
-/* progress report handler for lengthy operations
- * returns 0 to abort operation, nonzero to continue
- */
-int StdIoProgress(StdIoStream *st, ulonglong cur, ulonglong max) {
-  return 1;
-}
-
-longlong StdIoGetFileSize(StdIoStream *st) {
-	longlong epos = 0;
-	longlong cpos = ftello(st->fp);
-	fseeko(st->fp, 0, SEEK_END);
-	epos = ftello(st->fp);
-	fseeko(st->fp, cpos, SEEK_SET);
-	return epos;
-}
-
-void InitStdIoStream(StdIoStream *st) {
-	memset(st,0,sizeof(StdIoStream));
-	st->base.read = (int (*)(InputStream *,ulonglong,void *,int))StdIoRead;
-	st->base.scan = (longlong (*)(InputStream *,ulonglong,unsigned int))StdIoScan;
-	st->base.getcachesize =  (unsigned int (*)(InputStream *))StdIoGetCacheSize;
-	st->base.geterror = (const char *(*)(InputStream *))StdIoGetLastError;
-	st->base.memalloc = (void *(*)(InputStream *,size_t))StdIoMalloc;
-	st->base.memrealloc = (void *(*)(InputStream *,void *,size_t))StdIoRealloc;
-	st->base.memfree = (void (*)(InputStream *,void *))StdIoFree;
-	st->base.progress = (int (*)(InputStream *,ulonglong,ulonglong))StdIoProgress;
-	st->base.getfilesize = (longlong (*)(InputStream *))StdIoGetFileSize;
-}
diff --git a/aegisub/libffms/src/core/stdiostream.h b/aegisub/libffms/src/core/stdiostream.h
deleted file mode 100644
index 116b0e089..000000000
--- a/aegisub/libffms/src/core/stdiostream.h
+++ /dev/null
@@ -1,84 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#ifndef STDIOSTREAM_H
-#define STDIOSTREAM_H
-
-#undef __STRICT_ANSI__
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "matroskaparser.h"
-
-#define	CACHESIZE 65536
-
-/************\
-* Structures *
-\************/
-
-/* first we need to create an I/O object that the parser will use to read the
- * source file
- */
-struct StdIoStream {
-  struct InputStream base;
-  FILE *fp;
-  int error;
-};
-
-typedef struct StdIoStream StdIoStream;
-
-/***********\
-* Functions *
-\***********/
-
-/* read count bytes into buffer starting at file position pos
- * return the number of bytes read, -1 on error or 0 on EOF
- */
-int StdIoRead(StdIoStream *st, ulonglong pos, void *buffer, int count);
-
-/* scan for a signature sig(big-endian) starting at file position pos
- * return position of the first byte of signature or -1 if error/not found
- */
-longlong StdIoScan(StdIoStream *st, ulonglong start, unsigned signature);
-
-/* return cache size, this is used to limit readahead */
-unsigned StdIoGetCacheSize(StdIoStream *st);
-
-/* return last error message */
-const char *StdIoGetLastError(StdIoStream *st);
-
-/* memory allocation, this is done via stdlib */
-void *StdIoMalloc(StdIoStream *st, size_t size);
-
-void *StdIoRealloc(StdIoStream *st, void *mem, size_t size);
-
-void StdIoFree(StdIoStream *st, void *mem);
-
-/* progress report handler for lengthy operations
- * returns 0 to abort operation, nonzero to continue
- */
-int StdIoProgress(StdIoStream *st, ulonglong cur, ulonglong max);
-
-longlong StdIoGetFileSize(StdIoStream *st);
-
-void InitStdIoStream(StdIoStream *st);
-
-#endif /* #ifndef STDIOSTREAM_H */
diff --git a/aegisub/libffms/src/core/utils.cpp b/aegisub/libffms/src/core/utils.cpp
deleted file mode 100644
index a004dfa6c..000000000
--- a/aegisub/libffms/src/core/utils.cpp
+++ /dev/null
@@ -1,758 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include <string.h>
-#include <errno.h>
-#include "utils.h"
-#include "indexing.h"
-
-#ifdef _WIN32
-#	define WIN32_LEAN_AND_MEAN
-#	include <windows.h>
-#	include <io.h>
-#	include <fcntl.h>
-extern "C" {
-#	include "libavutil/avstring.h"
-}
-#endif // _WIN32
-
-
-// Export the array but not its data type... fun...
-typedef struct CodecTags{
-    char str[20];
-    enum CodecID id;
-} CodecTags;
-
-extern "C" {
-extern const AVCodecTag ff_codec_bmp_tags[];
-extern const CodecTags ff_mkv_codec_tags[];
-extern const AVCodecTag ff_codec_movvideo_tags[];
-extern const AVCodecTag ff_codec_wav_tags[];
-
-/* if you have this, we'll assume you have a new enough libavutil too */
-#if LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(0, 12, 0)
-#	include <libavutil/opt.h>
-#endif
-}
-
-extern int CPUFeatures;
-extern bool GlobalUseUTF8Paths;
-
-
-
-FFMS_Exception::FFMS_Exception(int ErrorType, int SubType, const char *Message) : _ErrorType(ErrorType), _SubType(SubType), _Message(Message) {
-}
-
-FFMS_Exception::FFMS_Exception(int ErrorType, int SubType, const std::string &Message) : _ErrorType(ErrorType), _SubType(SubType), _Message(Message) {
-}
-
-FFMS_Exception::~FFMS_Exception() throw () {
-}
-
-const std::string &FFMS_Exception::GetErrorMessage() const {
-	return _Message;
-}
-
-int FFMS_Exception::CopyOut(FFMS_ErrorInfo *ErrorInfo) const {
-	if (ErrorInfo) {
-		ErrorInfo->ErrorType = _ErrorType;
-		ErrorInfo->SubType = _SubType;
-
-		if (ErrorInfo->BufferSize > 0) {
-			memset(ErrorInfo->Buffer, 0, ErrorInfo->BufferSize);
-			_Message.copy(ErrorInfo->Buffer, ErrorInfo->BufferSize - 1);
-		}
-	}
-
-	return (_ErrorType << 16) | _SubType;
-}
-
-TrackCompressionContext::TrackCompressionContext(MatroskaFile *MF, TrackInfo *TI, unsigned int Track) {
-	CS = NULL;
-	CompressedPrivateData = NULL;
-	CompressedPrivateDataSize = 0;
-	CompressionMethod = TI->CompMethod;
-
-	if (CompressionMethod == COMP_ZLIB) {
-		char ErrorMessage[512];
-		CS = cs_Create(MF, Track, ErrorMessage, sizeof(ErrorMessage));
-		if (CS == NULL) {
-			std::ostringstream buf;
-			buf << "Can't create MKV track decompressor: " << ErrorMessage;
-			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, buf.str());
-		}
-	} else if (CompressionMethod == COMP_PREPEND) {
-		CompressedPrivateData		= TI->CompMethodPrivate;
-		CompressedPrivateDataSize	= TI->CompMethodPrivateSize;
-	} else {
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			"Can't create MKV track decompressor: unknown or unsupported compression method");
-	}
-}
-
-TrackCompressionContext::~TrackCompressionContext() {
-	if (CS)
-		cs_Destroy(CS);
-}
-
-int64_t GetSWSCPUFlags() {
-	int64_t Flags = 0;
-
-	if (CPUFeatures & FFMS_CPU_CAPS_MMX)
-		Flags |= SWS_CPU_CAPS_MMX;
-	if (CPUFeatures & FFMS_CPU_CAPS_MMX2)
-		Flags |= SWS_CPU_CAPS_MMX2;
-	if (CPUFeatures & FFMS_CPU_CAPS_3DNOW)
-		Flags |= SWS_CPU_CAPS_3DNOW;
-	if (CPUFeatures & FFMS_CPU_CAPS_ALTIVEC)
-		Flags |= SWS_CPU_CAPS_ALTIVEC;
-	if (CPUFeatures & FFMS_CPU_CAPS_BFIN)
-		Flags |= SWS_CPU_CAPS_BFIN;
-#ifdef SWS_CPU_CAPS_SSE2
-	if (CPUFeatures & FFMS_CPU_CAPS_SSE2)
-		Flags |= SWS_CPU_CAPS_SSE2;
-#endif
-
-	return Flags;
-}
-
-static int handle_jpeg(PixelFormat *format)
-{
-	switch (*format) {
-	case PIX_FMT_YUVJ420P: *format = PIX_FMT_YUV420P; return 1;
-	case PIX_FMT_YUVJ422P: *format = PIX_FMT_YUV422P; return 1;
-	case PIX_FMT_YUVJ444P: *format = PIX_FMT_YUV444P; return 1;
-	case PIX_FMT_YUVJ440P: *format = PIX_FMT_YUV440P; return 1;
-	default:                                          return 0;
-	}
-}
-SwsContext *GetSwsContext(int SrcW, int SrcH, PixelFormat SrcFormat, int DstW, int DstH, PixelFormat DstFormat, int64_t Flags, int ColorSpace) {
-#if LIBSWSCALE_VERSION_INT < AV_VERSION_INT(0, 12, 0)
-	return sws_getContext(SrcW, SrcH, SrcFormat, DstW, DstH, DstFormat, Flags, 0, 0, 0);
-#else
-	SwsContext *Context = sws_alloc_context();
-	if (!Context) return 0;
-
-	if (ColorSpace == -1)
-		ColorSpace = (SrcW > 1024 || SrcH >= 600) ? SWS_CS_ITU709 : SWS_CS_DEFAULT;
-
-	int SrcRange = handle_jpeg(&SrcFormat);
-	int DstRange = handle_jpeg(&DstFormat);
-
-	av_set_int(Context, "sws_flags", Flags);
-	av_set_int(Context, "srcw",       SrcW);
-	av_set_int(Context, "srch",       SrcH);
-	av_set_int(Context, "dstw",       DstW);
-	av_set_int(Context, "dsth",       DstH);
-	av_set_int(Context, "src_range",  SrcRange);
-	av_set_int(Context, "dst_range",  DstRange);
-	av_set_int(Context, "src_format", SrcFormat);
-	av_set_int(Context, "dst_format", DstFormat);
-
-	sws_setColorspaceDetails(Context, sws_getCoefficients(ColorSpace), SrcRange, sws_getCoefficients(ColorSpace), DstRange, 0, 1<<16, 1<<16);
-
-	if(sws_init_context(Context, 0, 0) < 0){
-		sws_freeContext(Context);
-		return 0;
-	}
-
-	return Context;
-#endif
-
-}
-
-
-int GetPPCPUFlags() {
-	int Flags = 0;
-
-#ifdef FFMS_USE_POSTPROC
-// not exactly a pretty solution but it'll never get called anyway
-	if (CPUFeatures & FFMS_CPU_CAPS_MMX)
-		Flags |= PP_CPU_CAPS_MMX;
-	if (CPUFeatures & FFMS_CPU_CAPS_MMX2)
-		Flags |= PP_CPU_CAPS_MMX2;
-	if (CPUFeatures & FFMS_CPU_CAPS_3DNOW)
-		Flags |= PP_CPU_CAPS_3DNOW;
-	if (CPUFeatures & FFMS_CPU_CAPS_ALTIVEC)
-		Flags |= PP_CPU_CAPS_ALTIVEC;
-#endif // FFMS_USE_POSTPROC
-
-	return Flags;
-}
-
-void ClearErrorInfo(FFMS_ErrorInfo *ErrorInfo) {
-	if (ErrorInfo) {
-		ErrorInfo->ErrorType = FFMS_ERROR_SUCCESS;
-		ErrorInfo->SubType = FFMS_ERROR_SUCCESS;
-
-		if (ErrorInfo->BufferSize > 0)
-			ErrorInfo->Buffer[0] = 0;
-	}
-}
-
-FFMS_TrackType HaaliTrackTypeToFFTrackType(int TT) {
-	switch (TT) {
-		case TT_VIDEO: return FFMS_TYPE_VIDEO; break;
-		case TT_AUDIO: return FFMS_TYPE_AUDIO; break;
-		case TT_SUB: return FFMS_TYPE_SUBTITLE; break;
-		default: return FFMS_TYPE_UNKNOWN;
-	}
-}
-
-const char *GetLAVCSampleFormatName(AVSampleFormat s) {
-	switch (s) {
-		case AV_SAMPLE_FMT_U8:	return "8-bit unsigned integer";
-		case AV_SAMPLE_FMT_S16:	return "16-bit signed integer";
-		case AV_SAMPLE_FMT_S32:	return "32-bit signed integer";
-		case AV_SAMPLE_FMT_FLT:	return "Single-precision floating point";
-		case AV_SAMPLE_FMT_DBL:	return "Double-precision floating point";
-		default:				return "Unknown";
-	}
-}
-
-template<class T> static void safe_realloc(T *&ptr, size_t size) {
-	void *newalloc = realloc(ptr, size);
-	if (newalloc) {
-		ptr = static_cast<T*>(newalloc);
-	}
-	else {
-		free(ptr);
-		ptr = 0;
-	}
-}
-
-void ReadFrame(uint64_t FilePos, unsigned int &FrameSize, TrackCompressionContext *TCC, MatroskaReaderContext &Context) {
-	if (TCC && TCC->CS) {
-		CompressedStream *CS = TCC->CS;
-		unsigned int DecompressedFrameSize = 0;
-
-		cs_NextFrame(CS, FilePos, FrameSize);
-
-		for (;;) {
-			int ReadBytes = cs_ReadData(CS, Context.CSBuffer, sizeof(Context.CSBuffer));
-			if (ReadBytes < 0) {
-				std::ostringstream buf;
-				buf << "Error decompressing data: " << cs_GetLastError(CS);
-				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, buf.str());
-			}
-
-			if (ReadBytes == 0) {
-				FrameSize = DecompressedFrameSize;
-				memset(Context.Buffer + DecompressedFrameSize, 0,
-					Context.BufferSize  + FF_INPUT_BUFFER_PADDING_SIZE - DecompressedFrameSize);
-				return;
-			}
-
-			if (Context.BufferSize < DecompressedFrameSize + ReadBytes) {
-				Context.BufferSize = DecompressedFrameSize + ReadBytes;
-				safe_realloc(Context.Buffer, Context.BufferSize + FF_INPUT_BUFFER_PADDING_SIZE);
-				if (Context.Buffer == NULL)
-					throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_ALLOCATION_FAILED,
-					"Out of memory");
-			}
-
-			memcpy(Context.Buffer + DecompressedFrameSize, Context.CSBuffer, ReadBytes);
-			DecompressedFrameSize += ReadBytes;
-		}
-	} else {
-		if (fseeko(Context.ST.fp, FilePos, SEEK_SET)) {
-			std::ostringstream buf;
-			buf << "fseek(): " << strerror(errno);
-			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_SEEKING, buf.str());
-		}
-
-		if (TCC && TCC->CompressionMethod == COMP_PREPEND) {
-			unsigned ReqBufsize = FrameSize + TCC->CompressedPrivateDataSize + 16;
-			if (Context.BufferSize < ReqBufsize) {
-				Context.BufferSize = FrameSize + TCC->CompressedPrivateDataSize;
-				safe_realloc(Context.Buffer, ReqBufsize);
-				if (Context.Buffer == NULL)
-					throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_ALLOCATION_FAILED, "Out of memory");
-			}
-
-			/* // maybe faster? maybe not?
-			for (int i=0; i < TCC->CompressedPrivateDataSize; i++)
-				*(Context.Buffer)++ = ((uint8_t *)TCC->CompressedPrivateData)[i];
-			*/
-			// screw it, memcpy and fuck the losers who use header compression
-			memcpy(Context.Buffer, TCC->CompressedPrivateData, TCC->CompressedPrivateDataSize);
-		}
-		else if (Context.BufferSize < FrameSize) {
-			Context.BufferSize = FrameSize;
-			safe_realloc(Context.Buffer, Context.BufferSize + 16);
-			if (Context.Buffer == NULL)
-				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_ALLOCATION_FAILED,
-					"Out of memory");
-		}
-
-		uint8_t *TargetPtr = Context.Buffer;
-		if (TCC && TCC->CompressionMethod == COMP_PREPEND)
-			TargetPtr += TCC->CompressedPrivateDataSize;
-
-		size_t ReadBytes = fread(TargetPtr, 1, FrameSize, Context.ST.fp);
-		if (ReadBytes != FrameSize) {
-			return;
-			if (ReadBytes == 0) {
-				if (feof(Context.ST.fp)) {
-					throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-						"Unexpected EOF while reading frame");
-				} else {
-					std::ostringstream buf;
-					buf << "Error reading frame: " << strerror(errno);
-					throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_SEEKING, buf.str());
-				}
-			} else {
-				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-					"Short read while reading frame");
-			}
-			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-				"Unknown read error");
-		}
-
-		return;
-	}
-}
-
-void InitNullPacket(AVPacket &pkt) {
-	av_init_packet(&pkt);
-	pkt.data = NULL;
-	pkt.size = 0;
-}
-
-void FillAP(FFMS_AudioProperties &AP, AVCodecContext *CTX, FFMS_Track &Frames) {
-	AP.SampleFormat = static_cast<FFMS_SampleFormat>(CTX->sample_fmt);
-	AP.BitsPerSample = av_get_bits_per_sample_fmt(CTX->sample_fmt);
-	if (CTX->sample_fmt == AV_SAMPLE_FMT_S32 && CTX->bits_per_raw_sample)
-		AP.BitsPerSample = CTX->bits_per_raw_sample;
-
-	AP.Channels = CTX->channels;;
-	AP.ChannelLayout = CTX->channel_layout;
-	AP.SampleRate = CTX->sample_rate;
-	if (Frames.size() > 0) {
-		AP.NumSamples = (Frames.back()).SampleStart + (Frames.back()).SampleCount;
-		AP.FirstTime = ((Frames.front().PTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
-		AP.LastTime = ((Frames.back().PTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
-	}
-}
-
-#ifdef HAALISOURCE
-
-unsigned vtSize(VARIANT &vt) {
-	if (V_VT(&vt) != (VT_ARRAY | VT_UI1))
-		return 0;
-	long lb,ub;
-	if (FAILED(SafeArrayGetLBound(V_ARRAY(&vt),1,&lb)) ||
-		FAILED(SafeArrayGetUBound(V_ARRAY(&vt),1,&ub)))
-		return 0;
-	return ub - lb + 1;
-}
-
-void vtCopy(VARIANT& vt,void *dest) {
-	unsigned sz = vtSize(vt);
-	if (sz > 0) {
-		void  *vp;
-		if (SUCCEEDED(SafeArrayAccessData(V_ARRAY(&vt),&vp))) {
-			memcpy(dest,vp,sz);
-			SafeArrayUnaccessData(V_ARRAY(&vt));
-		}
-	}
-}
-
-#endif
-
-CodecID MatroskaToFFCodecID(char *Codec, void *CodecPrivate, unsigned int FourCC, unsigned int BitsPerSample) {
-/* Look up native codecs */
-	for(int i = 0; ff_mkv_codec_tags[i].id != CODEC_ID_NONE; i++){
-		if(!strncmp(ff_mkv_codec_tags[i].str, Codec,
-			strlen(ff_mkv_codec_tags[i].str))) {
-
-				// Uncompressed and exotic format fixup
-				// This list is incomplete
-				CodecID CID = ff_mkv_codec_tags[i].id;
-				switch (CID) {
-					case CODEC_ID_PCM_S16LE:
-						switch (BitsPerSample) {
-							case 8: CID = CODEC_ID_PCM_S8; break;
-							case 16: CID = CODEC_ID_PCM_S16LE; break;
-							case 24: CID = CODEC_ID_PCM_S24LE; break;
-							case 32: CID = CODEC_ID_PCM_S32LE; break;
-						}
-						break;
-					case CODEC_ID_PCM_S16BE:
-						switch (BitsPerSample) {
-							case 8: CID = CODEC_ID_PCM_S8; break;
-							case 16: CID = CODEC_ID_PCM_S16BE; break;
-							case 24: CID = CODEC_ID_PCM_S24BE; break;
-							case 32: CID = CODEC_ID_PCM_S32BE; break;
-						}
-						break;
-					default:
-						break;
-				}
-
-				return CID;
-			}
-	}
-
-/* Video codecs for "avi in mkv" mode */
-	const AVCodecTag *const tags[] = { ff_codec_bmp_tags, 0 };
-
-	if (!strcmp(Codec, "V_MS/VFW/FOURCC")) {
-		FFMS_BITMAPINFOHEADER *b = reinterpret_cast<FFMS_BITMAPINFOHEADER *>(CodecPrivate);
-		return av_codec_get_id(tags, b->biCompression);
-	}
-
-	if (!strcmp(Codec, "V_FOURCC")) {
-		return av_codec_get_id(tags, FourCC);
-	}
-
-// FIXME
-/* Audio codecs for "acm in mkv" mode */
-		//#include "Mmreg.h"
-		//((WAVEFORMATEX *)TI->CodecPrivate)->wFormatTag
-
-/* Fixup for uncompressed video formats */
-
-/* Fixup for uncompressed audio formats */
-
-	return CODEC_ID_NONE;
-}
-
-void InitializeCodecContextFromMatroskaTrackInfo(TrackInfo *TI, AVCodecContext *CodecContext) {
-	CodecContext->extradata = static_cast<uint8_t *>(TI->CodecPrivate);
-	CodecContext->extradata_size = TI->CodecPrivateSize;
-
-	if (TI->Type == TT_VIDEO) {
-		CodecContext->coded_width = TI->AV.Video.PixelWidth;
-		CodecContext->coded_height = TI->AV.Video.PixelHeight;
-	} else if (TI->Type == TT_AUDIO) {
-		CodecContext->sample_rate = mkv_TruncFloat(TI->AV.Audio.SamplingFreq);
-		CodecContext->bits_per_coded_sample = TI->AV.Audio.BitDepth;
-		CodecContext->channels = TI->AV.Audio.Channels;
-	}
-}
-
-#ifdef HAALISOURCE
-
-FFCodecContext InitializeCodecContextFromHaaliInfo(CComQIPtr<IPropertyBag> pBag) {
-	CComVariant pV;
-	if (FAILED(pBag->Read(L"Type", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
-		return FFCodecContext();
-
-	unsigned int TT = pV.uintVal;
-
-	FFCodecContext CodecContext(avcodec_alloc_context(), DeleteHaaliCodecContext);
-
-	unsigned int FourCC = 0;
-	if (TT == TT_VIDEO) {
-		pV.Clear();
-		if (SUCCEEDED(pBag->Read(L"Video.PixelWidth", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
-			CodecContext->coded_width = pV.uintVal;
-
-		pV.Clear();
-		if (SUCCEEDED(pBag->Read(L"Video.PixelHeight", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
-			CodecContext->coded_height = pV.uintVal;
-
-		pV.Clear();
-		if (SUCCEEDED(pBag->Read(L"FOURCC", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
-			FourCC = pV.uintVal;
-
-		// Reconstruct the missing codec private part for VC1
-		FFMS_BITMAPINFOHEADER bih;
-		memset(&bih, 0, sizeof bih);
-		bih.biSize = sizeof bih;
-		bih.biCompression = FourCC;
-		bih.biBitCount = 24;
-		bih.biPlanes = 1;
-		bih.biHeight = CodecContext->coded_height;
-
-		pV.Clear();
-		if (SUCCEEDED(pBag->Read(L"CodecPrivate", &pV, NULL))) {
-			bih.biSize += vtSize(pV);
-			CodecContext->extradata = static_cast<uint8_t*>(av_malloc(bih.biSize));
-			memcpy(CodecContext->extradata, &bih, sizeof bih);
-			vtCopy(pV, CodecContext->extradata + sizeof bih);
-		}
-		else {
-			CodecContext->extradata = static_cast<uint8_t*>(av_malloc(bih.biSize));
-			memcpy(CodecContext->extradata, &bih, sizeof bih);
-		}
-		CodecContext->extradata_size = bih.biSize;
-	}
-	else if (TT == TT_AUDIO) {
-		pV.Clear();
-		if (SUCCEEDED(pBag->Read(L"CodecPrivate", &pV, NULL))) {
-			CodecContext->extradata_size = vtSize(pV);
-			CodecContext->extradata = static_cast<uint8_t*>(av_malloc(CodecContext->extradata_size));
-			vtCopy(pV, CodecContext->extradata);
-		}
-
-		pV.Clear();
-		if (SUCCEEDED(pBag->Read(L"Audio.SamplingFreq", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
-			CodecContext->sample_rate = pV.uintVal;
-
-		pV.Clear();
-		if (SUCCEEDED(pBag->Read(L"Audio.BitDepth", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
-			CodecContext->bits_per_coded_sample = pV.uintVal;
-
-		pV.Clear();
-		if (SUCCEEDED(pBag->Read(L"Audio.Channels", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
-			CodecContext->channels = pV.uintVal;
-	}
-
-	pV.Clear();
-	if (SUCCEEDED(pBag->Read(L"CodecID", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_BSTR))) {
-		char CodecStr[2048];
-		wcstombs(CodecStr, pV.bstrVal, 2000);
-
-		CodecContext->codec = avcodec_find_decoder(MatroskaToFFCodecID(CodecStr, CodecContext->extradata, FourCC, CodecContext->bits_per_coded_sample));
-	}
-	return CodecContext;
-}
-
-#endif
-
-
-// All this filename chikanery that follows is supposed to make sure both local
-// codepage (used by avisynth etc) and UTF8 (potentially used by API users) strings
-// work correctly on Win32.
-// It's a really ugly hack, and I blame Microsoft for it.
-#ifdef _WIN32
-static wchar_t *dup_char_to_wchar(const char *s, unsigned int cp) {
-	wchar_t *w;
-	int l;
-	if (!(l = MultiByteToWideChar(cp, MB_ERR_INVALID_CHARS, s, -1, NULL, 0)))
-		return NULL;
-	if (!(w = (wchar_t *)malloc(l * sizeof(wchar_t))))
-		return NULL;
-	if (MultiByteToWideChar(cp, MB_ERR_INVALID_CHARS, s, -1 , w, l) <= 0) {
-		free(w);
-		w = NULL;
-	}
-	return w;
-}
-#endif
-
-FILE *ffms_fopen(const char *filename, const char *mode) {
-#ifdef _WIN32
-	unsigned int codepage;
-	if (GlobalUseUTF8Paths)
-		codepage = CP_UTF8;
-	else
-		codepage = CP_ACP;
-
-	FILE *ret;
-	wchar_t *filename_wide	= dup_char_to_wchar(filename, codepage);
-	wchar_t *mode_wide		= dup_char_to_wchar(mode, codepage);
-	if (filename_wide && mode_wide)
-		ret = _wfopen(filename_wide, mode_wide);
-	else
-		ret = fopen(filename, mode);
-
-	free(filename_wide);
-	free(mode_wide);
-
-	return ret;
-#else
-	return fopen(filename, mode);
-#endif /* _WIN32 */
-}
-
-size_t ffms_mbstowcs (wchar_t *wcstr, const char *mbstr, size_t max) {
-#ifdef _WIN32
-	// this is only called by HaaliOpenFile anyway, so I think this is safe
-	return static_cast<size_t>(MultiByteToWideChar((GlobalUseUTF8Paths ? CP_UTF8 : CP_ACP), MB_ERR_INVALID_CHARS, mbstr, -1, wcstr, max));
-#else
-	return mbstowcs(wcstr, mbstr, max);
-#endif
-}
-
-
-// ffms_fstream stuff
-void ffms_fstream::open(const char *filename, std::ios_base::openmode mode) {
-	// Unlike MSVC, mingw's iostream library doesn't have an fstream overload
-	// that takes a wchar_t* filename, which means you can't open unicode
-	// filenames with it on Windows. gg.
-#if defined(_WIN32) && !defined(__MINGW32__)
-	unsigned int codepage = GlobalUseUTF8Paths ? CP_UTF8 : CP_ACP;
-
-	wchar_t *filename_wide = dup_char_to_wchar(filename, codepage);
-	if (filename_wide)
-		std::fstream::open(filename_wide, mode);
-	else
-		std::fstream::open(filename, mode);
-
-	free(filename_wide);
-#else // defined(_WIN32) && !defined(__MINGW32__)
-	std::fstream::open(filename, mode);
-#endif // defined(_WIN32) && !defined(__MINGW32__)
-}
-
-ffms_fstream::ffms_fstream(const char *filename, std::ios_base::openmode mode) {
-	open(filename, mode);
-}
-
-
-#ifdef _WIN32
-int ffms_wchar_open(const char *fname, int oflags, int pmode) {
-    wchar_t *wfname = dup_char_to_wchar(fname, CP_UTF8);
-    if (wfname) {
-        int ret = _wopen(wfname, oflags, pmode);
-        free(wfname);
-        return ret;
-    }
-    return -1;
-}
-
-static int ffms_lavf_file_open(URLContext *h, const char *filename, int flags) {
-    int access;
-    int fd;
-
-    av_strstart(filename, "file:", &filename);
-
-    if (flags & URL_RDWR) {
-        access = _O_CREAT | _O_TRUNC | _O_RDWR;
-    } else if (flags & URL_WRONLY) {
-        access = _O_CREAT | _O_TRUNC | _O_WRONLY;
-    } else {
-        access = _O_RDONLY;
-    }
-#ifdef _O_BINARY
-    access |= _O_BINARY;
-#endif
-    fd = ffms_wchar_open(filename, access, 0666);
-    if (fd == -1)
-        return AVERROR(ENOENT);
-    h->priv_data = (void *) (intptr_t) fd;
-    return 0;
-}
-
-// Hijack lavf's file protocol handler's open function and use our own instead.
-// Hack by nielsm.
-void ffms_patch_lavf_file_open() {
-	extern URLProtocol *first_protocol;
-	URLProtocol *proto = first_protocol;
-	while (proto != NULL) {
-		if (strcmp("file", proto->name) == 0) {
-			break;
-		}
-		proto = proto->next;
-	}
-	if (proto != NULL) {
-		proto->url_open = &ffms_lavf_file_open;
-	}
-}
-#endif // _WIN32
-
-// End of filename hackery.
-
-
-#ifdef HAALISOURCE
-
-CComPtr<IMMContainer> HaaliOpenFile(const char *SourceFile, enum FFMS_Sources SourceMode) {
-	CComPtr<IMMContainer> pMMC;
-
-	CLSID clsid = HAALI_MPEG_PARSER;
-	if (SourceMode == FFMS_SOURCE_HAALIOGG)
-		clsid = HAALI_OGG_PARSER;
-
-	if (FAILED(pMMC.CoCreateInstance(clsid)))
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_ALLOCATION_FAILED,
-			"Can't create parser");
-
-	CComPtr<IMemAlloc> pMA;
-	if (FAILED(pMA.CoCreateInstance(CLSID_MemAlloc)))
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_ALLOCATION_FAILED,
-			"Can't create memory allocator");
-
-	CComPtr<IMMStream> pMS;
-	if (FAILED(pMS.CoCreateInstance(CLSID_DiskFile)))
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_ALLOCATION_FAILED,
-			"Can't create disk file reader");
-
-	WCHAR WSourceFile[2048];
-	ffms_mbstowcs(WSourceFile, SourceFile, 2000);
-	CComQIPtr<IMMStreamOpen> pMSO(pMS);
-	if (FAILED(pMSO->Open(WSourceFile)))
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			"Can't open file");
-
-	if (FAILED(pMMC->Open(pMS, 0, NULL, pMA))) {
-		if (SourceMode == FFMS_SOURCE_HAALIMPEG)
-			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_INVALID_ARGUMENT,
-				"Can't parse file, most likely a transport stream not cut at packet boundaries");
-		else
-			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_INVALID_ARGUMENT,
-				"Can't parse file");
-	}
-
-	return pMMC;
-}
-
-#endif
-
-void LAVFOpenFile(const char *SourceFile, AVFormatContext *&FormatContext) {
-	if (av_open_input_file(&FormatContext, SourceFile, NULL, 0, NULL) != 0)
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			std::string("Couldn't open '") + SourceFile + "'");
-
-	if (av_find_stream_info(FormatContext) < 0) {
-		av_close_input_file(FormatContext);
-		FormatContext = NULL;
-		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
-			"Couldn't find stream information");
-	}
-}
-
-
-// attempt to correct framerate to the proper NTSC fraction, if applicable
-// code stolen from Perian
-void CorrectNTSCRationalFramerate(int *Num, int *Den) {
-	AVRational TempFPS;
-	TempFPS.den = *Num; // not a typo
-	TempFPS.num = *Den; // still not a typo
-
-	av_reduce(&TempFPS.num, &TempFPS.den, TempFPS.num, TempFPS.den, INT_MAX);
-
-	if (TempFPS.num == 1) {
-		*Num = TempFPS.den;
-		*Den = TempFPS.num;
-	}
-	else {
-		double FTimebase = av_q2d(TempFPS);
-		double NearestNTSC = floor(FTimebase * 1001.0 + 0.5) / 1001.0;
-		const double SmallInterval = 1.0/120.0;
-
-		if (fabs(FTimebase - NearestNTSC) < SmallInterval) {
-			*Num = int((1001.0 / FTimebase) + 0.5);
-			*Den = 1001;
-		}
-	}
-}
-
-// correct the timebase if it is invalid
-void CorrectTimebase(FFMS_VideoProperties *VP, FFMS_TrackTimeBase *TTimebase) {
-	double Timebase = (double)TTimebase->Num / TTimebase->Den;
-	double FPS = (double)VP->FPSNumerator / VP->FPSDenominator;
-	if ((1000/Timebase) / FPS < 1) {
-		TTimebase->Den = VP->FPSNumerator;
-		TTimebase->Num = (int64_t)VP->FPSDenominator * 1000;
-	}
-}
diff --git a/aegisub/libffms/src/core/utils.h b/aegisub/libffms/src/core/utils.h
deleted file mode 100644
index 0370a309b..000000000
--- a/aegisub/libffms/src/core/utils.h
+++ /dev/null
@@ -1,232 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#ifndef UTILS_H
-#define UTILS_H
-
-#include <vector>
-#include <sstream>
-#include <fstream>
-#include <cstdio>
-#include "ffms.h"
-#include "matroskaparser.h"
-
-extern "C" {
-#include "stdiostream.h"
-#include <libavutil/mem.h>
-#include <libavformat/avformat.h>
-#include <libavcodec/avcodec.h>
-#include <libswscale/swscale.h>
-#ifdef FFMS_USE_POSTPROC
-#include <libpostproc/postprocess.h>
-#endif // FFMS_USE_POSTPROC
-}
-
-// must be included after ffmpeg headers
-#include "ffmscompat.h"
-
-#ifdef HAALISOURCE
-#	define WIN32_LEAN_AND_MEAN
-#	define _WIN32_DCOM
-#	include <windows.h>
-#	include <tchar.h>
-#	include <atlbase.h>
-#	include <dshow.h>
-#	include <initguid.h>
-#	include "CoParser.h"
-#	include "guids.h"
-#endif
-
-#define FFMS_GET_VECTOR_PTR(v) (((v).size() ? &(v)[0] : NULL))
-
-const int64_t ffms_av_nopts_value = static_cast<int64_t>(1) << 63;
-
-// used for matroska<->ffmpeg codec ID mapping to avoid Win32 dependency
-typedef struct FFMS_BITMAPINFOHEADER {
-	uint32_t      biSize;
-	int32_t       biWidth;
-	int32_t       biHeight;
-	uint16_t      biPlanes;
-	uint16_t      biBitCount;
-	uint32_t      biCompression;
-	uint32_t      biSizeImage;
-	int32_t       biXPelsPerMeter;
-	int32_t       biYPelsPerMeter;
-	uint32_t      biClrUsed;
-	uint32_t      biClrImportant;
-} FFMS_BITMAPINFOHEADER;
-
-class FFMS_Exception : public std::exception {
-private:
-	std::string _Message;
-	int _ErrorType;
-	int _SubType;
-public:
-	FFMS_Exception(int ErrorType, int SubType, const char *Message = "");
-	FFMS_Exception(int ErrorType, int SubType, const std::string &Message);
-	~FFMS_Exception() throw ();
-	const std::string &GetErrorMessage() const;
-	int CopyOut(FFMS_ErrorInfo *ErrorInfo) const;
-};
-
-template<class T>
-class FFSourceResources {
-private:
-	T *_PrivClass;
-	bool _Enabled;
-	bool _Arg;
-public:
-	FFSourceResources(T *Target) : _PrivClass(Target), _Enabled(true), _Arg(false) {
-	}
-
-	~FFSourceResources() {
-		if (_Enabled)
-			_PrivClass->Free(_Arg);
-	}
-
-	void SetEnabled(bool Enabled) {
-		_Enabled = Enabled;
-	}
-
-	void SetArg(bool Arg) {
-		_Arg = Arg;
-	}
-
-	void CloseCodec(bool Arg) {
-		_Arg = Arg;
-	}
-};
-// auto_ptr-ish holder for AVCodecContexts with overridable deleter
-class FFCodecContext {
-	AVCodecContext *CodecContext;
-	void (*Deleter)(AVCodecContext *);
-public:
-	FFCodecContext() : CodecContext(0), Deleter(0) { }
-	FFCodecContext(FFCodecContext &r) : CodecContext(r.CodecContext), Deleter(r.Deleter) { r.CodecContext = 0; }
-	FFCodecContext(AVCodecContext *c, void (*d)(AVCodecContext *)) : CodecContext(c), Deleter(d) { }
-	FFCodecContext& operator=(FFCodecContext r) { reset(r.CodecContext, r.Deleter); r.CodecContext = 0; return *this; }
-	~FFCodecContext() { reset(); }
-	AVCodecContext* operator->() { return CodecContext; }
-	operator AVCodecContext*() { return CodecContext; }
-	void reset(AVCodecContext *c = 0, void (*d)(AVCodecContext *) = 0) {
-		if (CodecContext && Deleter) Deleter(CodecContext);
-		CodecContext = c;
-		Deleter = d;
-	}
-};
-
-inline void DeleteHaaliCodecContext(AVCodecContext *CodecContext) {
-	av_freep(&CodecContext->extradata);
-	av_freep(&CodecContext);
-}
-inline void DeleteMatroskaCodecContext(AVCodecContext *CodecContext) {
-	avcodec_close(CodecContext);
-	av_freep(&CodecContext);
-}
-
-struct MatroskaReaderContext {
-public:
-	StdIoStream ST;
-	uint8_t *Buffer;
-	unsigned int BufferSize;
-	char CSBuffer[4096];
-
-	MatroskaReaderContext() {
-		InitStdIoStream(&ST);
-		Buffer = NULL;
-		BufferSize = 0;
-	}
-
-	~MatroskaReaderContext() {
-		free(Buffer);
-		if (ST.fp) fclose(ST.fp);
-	}
-};
-
-class ffms_fstream : public std::fstream {
-public:
-	void open(const char *filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out);
-	ffms_fstream(const char *filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out);
-};
-
-template <typename T>
-class AlignedBuffer {
-	T *buf;
-
-public:
-	AlignedBuffer(size_t n = 1) {
-		buf = (T*) av_malloc(sizeof(*buf) * n);
-		if (!buf) throw std::bad_alloc();
-	}
-
-	~AlignedBuffer() {
-		av_free(buf);
-		buf = 0;
-	}
-
-	const T &operator[] (size_t i) const { return buf[i]; }
-	T &operator[] (size_t i) { return buf[i]; }
-};
-
-
-class TrackCompressionContext {
-public:
-	CompressedStream *CS;
-	unsigned CompressionMethod;
-	void *CompressedPrivateData;
-	unsigned CompressedPrivateDataSize;
-
-	TrackCompressionContext(MatroskaFile *MF, TrackInfo *TI, unsigned int Track);
-	~TrackCompressionContext();
-};
-
-
-int64_t GetSWSCPUFlags();
-SwsContext *GetSwsContext(int SrcW, int SrcH, PixelFormat SrcFormat, int DstW, int DstH, PixelFormat DstFormat, int64_t Flags, int ColorSpace = -1);
-int GetPPCPUFlags();
-void ClearErrorInfo(FFMS_ErrorInfo *ErrorInfo);
-FFMS_TrackType HaaliTrackTypeToFFTrackType(int TT);
-void ReadFrame(uint64_t FilePos, unsigned int &FrameSize, TrackCompressionContext *TCC, MatroskaReaderContext &Context);
-bool AudioFMTIsFloat(AVSampleFormat FMT);
-void InitNullPacket(AVPacket &pkt);
-void FillAP(FFMS_AudioProperties &AP, AVCodecContext *CTX, FFMS_Track &Frames);
-
-#ifdef HAALISOURCE
-unsigned vtSize(VARIANT &vt);
-void vtCopy(VARIANT& vt,void *dest);
-FFCodecContext InitializeCodecContextFromHaaliInfo(CComQIPtr<IPropertyBag> pBag);
-#endif
-
-void InitializeCodecContextFromMatroskaTrackInfo(TrackInfo *TI, AVCodecContext *CodecContext);
-CodecID MatroskaToFFCodecID(char *Codec, void *CodecPrivate, unsigned int FourCC = 0, unsigned int BitsPerSample = 0);
-FILE *ffms_fopen(const char *filename, const char *mode);
-size_t ffms_mbstowcs (wchar_t *wcstr, const char *mbstr, size_t max);
-#ifdef _WIN32
-void ffms_patch_lavf_file_open();
-#endif // _WIN32
-#ifdef HAALISOURCE
-CComPtr<IMMContainer> HaaliOpenFile(const char *SourceFile, enum FFMS_Sources SourceMode);
-#endif // HAALISOURCE
-void LAVFOpenFile(const char *SourceFile, AVFormatContext *&FormatContext);
-void CorrectNTSCRationalFramerate(int *Num, int *Den);
-void CorrectTimebase(FFMS_VideoProperties *VP, FFMS_TrackTimeBase *TTimebase);
-const char *GetLAVCSampleFormatName(AVSampleFormat s);
-
-#endif
diff --git a/aegisub/libffms/src/core/videosource.cpp b/aegisub/libffms/src/core/videosource.cpp
deleted file mode 100644
index 1c3d5dcdb..000000000
--- a/aegisub/libffms/src/core/videosource.cpp
+++ /dev/null
@@ -1,296 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include "videosource.h"
-
-void FFMS_VideoSource::GetFrameCheck(int n) {
-	if (n < 0 || n >= VP.NumFrames)
-		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_INVALID_ARGUMENT,
-			"Out of bounds frame requested");
-}
-
-void FFMS_VideoSource::SetPP(const char *PP) {
-
-#ifdef FFMS_USE_POSTPROC
-	if (PPMode)
-		pp_free_mode(PPMode);
-	PPMode = NULL;
-
-	if (PP != NULL && strcmp(PP, "")) {
-		PPMode = pp_get_mode_by_name_and_quality(PP, PP_QUALITY_MAX);
-		if (!PPMode) {
-			ResetPP();
-			throw FFMS_Exception(FFMS_ERROR_POSTPROCESSING, FFMS_ERROR_INVALID_ARGUMENT,
-				"Invalid postprocesing settings");
-		}
-		
-	}
-
-	ReAdjustPP(CodecContext->pix_fmt, CodecContext->width, CodecContext->height);
-	OutputFrame(DecodeFrame);
-#else
-	throw FFMS_Exception(FFMS_ERROR_POSTPROCESSING, FFMS_ERROR_UNSUPPORTED,
-		"FFMS2 was not compiled with postprocessing support");
-#endif /* FFMS_USE_POSTPROC */
-}
-
-void FFMS_VideoSource::ResetPP() {
-#ifdef FFMS_USE_POSTPROC
-	if (PPContext)
-		pp_free_context(PPContext);
-	PPContext = NULL;
-
-	if (PPMode)
-		pp_free_mode(PPMode);
-	PPMode = NULL;
-
-#endif /* FFMS_USE_POSTPROC */
-	OutputFrame(DecodeFrame);
-}
-
-void FFMS_VideoSource::ReAdjustPP(PixelFormat VPixelFormat, int Width, int Height) {
-#ifdef FFMS_USE_POSTPROC
-	if (PPContext)
-		pp_free_context(PPContext);
-	PPContext = NULL;
-
-	if (!PPMode)
-		return;
-
-	int Flags =  GetPPCPUFlags();
-
-	switch (VPixelFormat) {
-		case PIX_FMT_YUV420P:
-		case PIX_FMT_YUVJ420P:
-			Flags |= PP_FORMAT_420; break;
-		case PIX_FMT_YUV422P:
-		case PIX_FMT_YUVJ422P:
-			Flags |= PP_FORMAT_422; break;
-		case PIX_FMT_YUV411P:
-			Flags |= PP_FORMAT_411; break;
-		case PIX_FMT_YUV444P:
-		case PIX_FMT_YUVJ444P:
-			Flags |= PP_FORMAT_444; break;
-		default:
-			ResetPP();
-			throw FFMS_Exception(FFMS_ERROR_POSTPROCESSING, FFMS_ERROR_UNSUPPORTED,
-				"The video does not have a colorspace suitable for postprocessing");
-	}
-
-	PPContext = pp_get_context(Width, Height, Flags);
-
-	avpicture_free(&PPFrame);
-	avpicture_alloc(&PPFrame, VPixelFormat, Width, Height);
-#else
-	return;
-#endif /* FFMS_USE_POSTPROC */
-
-}
-
-
-static void CopyAVPictureFields(AVPicture &Picture, FFMS_Frame &Dst) {
-	for (int i = 0; i < 4; i++) {
-		Dst.Data[i] = Picture.data[i];
-		Dst.Linesize[i] = Picture.linesize[i];
-	}
-}
-
-FFMS_Frame *FFMS_VideoSource::OutputFrame(AVFrame *Frame) {
-	if (LastFrameWidth != CodecContext->width || LastFrameHeight != CodecContext->height || LastFramePixelFormat != CodecContext->pix_fmt) {
-		ReAdjustPP(CodecContext->pix_fmt, CodecContext->width, CodecContext->height);
-
-		if (TargetHeight > 0 && TargetWidth > 0 && TargetPixelFormats != 0)
-			ReAdjustOutputFormat(TargetPixelFormats, TargetWidth, TargetHeight, TargetResizer);
-	}
-
-#ifdef FFMS_USE_POSTPROC
-	if (PPMode) {
-		pp_postprocess(const_cast<const uint8_t **>(Frame->data), Frame->linesize, PPFrame.data, PPFrame.linesize, CodecContext->width, CodecContext->height, Frame->qscale_table, Frame->qstride, PPMode, PPContext, Frame->pict_type | (Frame->qscale_type ? PP_PICT_TYPE_QP2 : 0));
-		if (SWS) {
-			sws_scale(SWS, const_cast<FFMS_SWS_CONST_PARAM uint8_t **>(PPFrame.data), PPFrame.linesize, 0, CodecContext->height, SWSFrame.data, SWSFrame.linesize);
-			CopyAVPictureFields(SWSFrame, LocalFrame);
-		} else {
-			CopyAVPictureFields(PPFrame, LocalFrame);			
-		}
-	} else {
-		if (SWS) {
-			sws_scale(SWS, const_cast<FFMS_SWS_CONST_PARAM uint8_t **>(Frame->data), Frame->linesize, 0, CodecContext->height, SWSFrame.data, SWSFrame.linesize);
-			CopyAVPictureFields(SWSFrame, LocalFrame);
-		} else {
-			// Special case to avoid ugly casts
-			for (int i = 0; i < 4; i++) {
-				LocalFrame.Data[i] = Frame->data[i];
-				LocalFrame.Linesize[i] = Frame->linesize[i];
-			}		
-		}		
-	}
-#else // FFMS_USE_POSTPROC
-	if (SWS) {
-		sws_scale(SWS, const_cast<FFMS_SWS_CONST_PARAM uint8_t **>(Frame->data), Frame->linesize, 0, CodecContext->height, SWSFrame.data, SWSFrame.linesize);
-		CopyAVPictureFields(SWSFrame, LocalFrame);
-	} else {
-		// Special case to avoid ugly casts
-		for (int i = 0; i < 4; i++) {
-			LocalFrame.Data[i] = Frame->data[i];
-			LocalFrame.Linesize[i] = Frame->linesize[i];
-		}		
-	}		
-#endif // FFMS_USE_POSTPROC
-
-	LocalFrame.EncodedWidth = CodecContext->width;
-	LocalFrame.EncodedHeight = CodecContext->height;
-	LocalFrame.EncodedPixelFormat = CodecContext->pix_fmt;
-	LocalFrame.ScaledWidth = TargetWidth;
-	LocalFrame.ScaledHeight = TargetHeight;
-	LocalFrame.ConvertedPixelFormat = OutputFormat;
-	LocalFrame.KeyFrame = Frame->key_frame;
-	LocalFrame.PictType = av_get_pict_type_char(Frame->pict_type);
-	LocalFrame.RepeatPict = Frame->repeat_pict;
-	LocalFrame.InterlacedFrame = Frame->interlaced_frame;
-	LocalFrame.TopFieldFirst = Frame->top_field_first;
-
-	LastFrameHeight = CodecContext->height;
-	LastFrameWidth = CodecContext->width;
-	LastFramePixelFormat = CodecContext->pix_fmt;
-
-	return &LocalFrame;
-}
-
-FFMS_VideoSource::FFMS_VideoSource(const char *SourceFile, FFMS_Index *Index, int Track) {
-	if (Track < 0 || Track >= static_cast<int>(Index->size()))
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
-			"Out of bounds track index selected");
-
-	if (Index->at(Track).TT != FFMS_TYPE_VIDEO)
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
-			"Not a video track");
-
-	if (Index->at(Track).size() == 0)
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
-			"Video track contains no frames");
-
-	if (!Index->CompareFileSignature(SourceFile))
-		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_MISMATCH,
-			"The index does not match the source file");
-
-	memset(&VP, 0, sizeof(VP));
-#ifdef FFMS_USE_POSTPROC
-	PPContext = NULL;
-	PPMode = NULL;
-#endif // FFMS_USE_POSTPROC
-	SWS = NULL;
-	LastFrameNum = 0;
-	CurrentFrame = 1;
-	DelayCounter = 0;
-	InitialDecode = 1;
-	CodecContext = NULL;
-	LastFrameHeight = -1;
-	LastFrameWidth = -1;
-	LastFramePixelFormat = PIX_FMT_NONE;
-	TargetHeight = -1;
-	TargetWidth = -1;
-	TargetPixelFormats = 0;
-	TargetResizer = 0;
-	OutputFormat = PIX_FMT_NONE;
-	DecodeFrame = avcodec_alloc_frame();
-
-	// Dummy allocations so the unallocated case doesn't have to be handled later
-#ifdef FFMS_USE_POSTPROC
-	avpicture_alloc(&PPFrame, PIX_FMT_GRAY8, 16, 16);
-#endif // FFMS_USE_POSTPROC
-	avpicture_alloc(&SWSFrame, PIX_FMT_GRAY8, 16, 16);
-}
-
-FFMS_VideoSource::~FFMS_VideoSource() {
-#ifdef FFMS_USE_POSTPROC
-	if (PPMode)
-		pp_free_mode(PPMode);
-
-	if (PPContext)
-		pp_free_context(PPContext);
-
-	avpicture_free(&PPFrame);
-#endif // FFMS_USE_POSTPROC
-
-	if (SWS)
-		sws_freeContext(SWS);
-
-	avpicture_free(&SWSFrame);
-	av_freep(&DecodeFrame);
-}
-
-FFMS_Frame *FFMS_VideoSource::GetFrameByTime(double Time) {
-	int Frame = Frames.ClosestFrameFromPTS(static_cast<int64_t>((Time * 1000 * Frames.TB.Den) / Frames.TB.Num));
-	return GetFrame(Frame);
-}
-
-void FFMS_VideoSource::SetOutputFormat(int64_t TargetFormats, int Width, int Height, int Resizer) {
-	this->TargetWidth = Width;
-	this->TargetHeight = Height;
-	this->TargetPixelFormats = TargetFormats;
-	this->TargetResizer = Resizer;
-	ReAdjustOutputFormat(TargetFormats, Width, Height, Resizer);
-	OutputFrame(DecodeFrame);
-}
-
-void FFMS_VideoSource::ReAdjustOutputFormat(int64_t TargetFormats, int Width, int Height, int Resizer) {
-	if (SWS) {
-		sws_freeContext(SWS);
-		SWS = NULL;
-	}
-
-	int Loss;
-	OutputFormat = avcodec_find_best_pix_fmt(TargetFormats,
-		CodecContext->pix_fmt, 1 /* Required to prevent pointless RGB32 => RGB24 conversion */, &Loss);
-	if (OutputFormat == PIX_FMT_NONE) {
-		ResetOutputFormat();
-		throw FFMS_Exception(FFMS_ERROR_SCALING, FFMS_ERROR_INVALID_ARGUMENT,
-			"No suitable output format found");
-	}
-
-	if (CodecContext->pix_fmt != OutputFormat || Width != CodecContext->width || Height != CodecContext->height) {
-		int ColorSpace = CodecContext->colorspace;
-		if (ColorSpace == AVCOL_SPC_UNSPECIFIED) ColorSpace = -1;
-		SWS = GetSwsContext(CodecContext->width, CodecContext->height, CodecContext->pix_fmt, Width, Height,
-			OutputFormat, GetSWSCPUFlags() | Resizer, ColorSpace);
-		if (SWS == NULL) {
-			ResetOutputFormat();
-			throw FFMS_Exception(FFMS_ERROR_SCALING, FFMS_ERROR_INVALID_ARGUMENT,
-				"Failed to allocate SWScale context");
-		}
-	}
-
-	avpicture_free(&SWSFrame);
-	avpicture_alloc(&SWSFrame, OutputFormat, Width, Height);
-}
-
-void FFMS_VideoSource::ResetOutputFormat() {
-	if (SWS) {
-		sws_freeContext(SWS);
-		SWS = NULL;
-	}
-
-	TargetWidth = -1;
-	TargetHeight = -1;
-	TargetPixelFormats = 0;
-	OutputFormat = PIX_FMT_NONE;
-	
-	OutputFrame(DecodeFrame);
-}
diff --git a/aegisub/libffms/src/core/videosource.h b/aegisub/libffms/src/core/videosource.h
deleted file mode 100644
index ee4f92dcc..000000000
--- a/aegisub/libffms/src/core/videosource.h
+++ /dev/null
@@ -1,151 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#ifndef FFVIDEOSOURCE_H
-#define FFVIDEOSOURCE_H
-
-extern "C" {
-#include <libavformat/avformat.h>
-#include <libavcodec/avcodec.h>
-#include <libswscale/swscale.h>
-#ifdef FFMS_USE_POSTPROC
-#include <libpostproc/postprocess.h>
-#endif // FFMS_USE_POSTPROC
-}
-
-// must be included after ffmpeg headers
-#include "ffmscompat.h"
-
-#include <vector>
-#include <sstream>
-#include "indexing.h"
-#include "utils.h"
-#include "ffms.h"
-
-#ifdef HAALISOURCE
-#	define WIN32_LEAN_AND_MEAN
-#	define _WIN32_DCOM
-#	include <windows.h>
-#	include <tchar.h>
-#	include <atlbase.h>
-#	include <dshow.h>
-#	include <initguid.h>
-#	include "CoParser.h"
-#	include "guids.h"
-#endif
-
-class FFMS_VideoSource {
-friend class FFSourceResources<FFMS_VideoSource>;
-private:
-#ifdef FFMS_USE_POSTPROC
-	pp_context_t *PPContext;
-	pp_mode_t *PPMode;
-#endif // FFMS_USE_POSTPROC
-	SwsContext *SWS;
-	int LastFrameHeight;
-	int LastFrameWidth;
-	PixelFormat LastFramePixelFormat;
-	int TargetHeight;
-	int TargetWidth;
-	int64_t TargetPixelFormats;
-	int TargetResizer;
-	PixelFormat OutputFormat;
-	AVPicture PPFrame;
-	AVPicture SWSFrame;
-protected:
-	FFMS_VideoProperties VP;
-	FFMS_Frame LocalFrame;
-	AVFrame *DecodeFrame;
-	int LastFrameNum;
-	FFMS_Track Frames;
-	int VideoTrack;
-	int	CurrentFrame;
-	int DelayCounter;
-	int InitialDecode;
-	AVCodecContext *CodecContext;
-
-	FFMS_VideoSource(const char *SourceFile, FFMS_Index *Index, int Track);
-	void ReAdjustPP(PixelFormat VPixelFormat, int Width, int Height);
-	void ReAdjustOutputFormat(int64_t TargetFormats, int Width, int Height, int Resizer);
-	FFMS_Frame *OutputFrame(AVFrame *Frame);
-	virtual void Free(bool CloseCodec) = 0;
-public:
-	virtual ~FFMS_VideoSource();
-	const FFMS_VideoProperties& GetVideoProperties() { return VP; }
-	FFMS_Track *GetTrack() { return &Frames; }
-	virtual FFMS_Frame *GetFrame(int n) = 0;
-	void GetFrameCheck(int n);
-	FFMS_Frame *GetFrameByTime(double Time);
-	void SetPP(const char *PP);
-	void ResetPP();
-	void SetOutputFormat(int64_t TargetFormats, int Width, int Height, int Resizer);
-	void ResetOutputFormat();
-};
-
-class FFLAVFVideo : public FFMS_VideoSource {
-private:
-	AVFormatContext *FormatContext;
-	int SeekMode;
-	FFSourceResources<FFMS_VideoSource> Res;
-
-	void DecodeNextFrame(int64_t *PTS);
-protected:
-	void Free(bool CloseCodec);
-public:
-	FFLAVFVideo(const char *SourceFile, int Track, FFMS_Index *Index, int Threads, int SeekMode);
-	FFMS_Frame *GetFrame(int n);
-};
-
-class FFMatroskaVideo : public FFMS_VideoSource {
-private:
-	MatroskaFile *MF;
-	MatroskaReaderContext MC;
-	TrackCompressionContext *TCC;
-	char ErrorMessage[256];
-	FFSourceResources<FFMS_VideoSource> Res;
-	size_t PacketNumber;
-
-	void DecodeNextFrame();
-protected:
-	void Free(bool CloseCodec);
-public:
-	FFMatroskaVideo(const char *SourceFile, int Track, FFMS_Index *Index, int Threads);
-	FFMS_Frame *GetFrame(int n);
-};
-
-#ifdef HAALISOURCE
-
-class FFHaaliVideo : public FFMS_VideoSource {
-	FFCodecContext HCodecContext;
-	CComPtr<IMMContainer> pMMC;
-	AVBitStreamFilterContext *BitStreamFilter;
-	FFSourceResources<FFMS_VideoSource> Res;
-
-	void DecodeNextFrame(int64_t *AFirstStartTime);
-protected:
-	void Free(bool CloseCodec);
-public:
-	FFHaaliVideo(const char *SourceFile, int Track, FFMS_Index *Index, int Threads, enum FFMS_Sources SourceMode);
-	FFMS_Frame *GetFrame(int n);
-};
-
-#endif // HAALISOURCE
-
-#endif
diff --git a/aegisub/libffms/src/core/wave64writer.cpp b/aegisub/libffms/src/core/wave64writer.cpp
deleted file mode 100644
index c2d82f202..000000000
--- a/aegisub/libffms/src/core/wave64writer.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#include "wave64writer.h"
-#include <string.h>
-
-#define WAVE_FORMAT_IEEE_FLOAT 0x0003
-#define WAVE_FORMAT_PCM 1
-
-static const uint8_t GuidRIFF[16]={
-	// {66666972-912E-11CF-A5D6-28DB04C10000}
-	0x72, 0x69, 0x66, 0x66, 0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00
-};
-
-static const uint8_t GuidWAVE[16]={
-	// {65766177-ACF3-11D3-8CD1-00C04F8EDB8A}
-	0x77, 0x61, 0x76, 0x65, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
-};
-
-static const uint8_t Guidfmt[16]={
-	// {20746D66-ACF3-11D3-8CD1-00C04F8EDB8A}
-	0x66, 0x6D, 0x74, 0x20, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
-};
-
-static const uint8_t Guiddata[16]={
-	// {61746164-ACF3-11D3-8CD1-00C04F8EDB8A}
-	0x64, 0x61, 0x74, 0x61, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
-};
-
-Wave64Writer::Wave64Writer(const char *Filename, uint16_t BitsPerSample, uint16_t Channels, uint32_t SamplesPerSec, bool IsFloat) : WavFile(Filename, std::ios::out | std::ios::binary | std::ios::trunc) {
-	BytesWritten = 0;
-	this->BitsPerSample = BitsPerSample;
-	this->Channels = Channels;
-	this->SamplesPerSec = SamplesPerSec;
-	this->IsFloat = IsFloat;
-
-	if (!WavFile.is_open())
-		throw "Failed to open destination file for writing";
-
-	WriteHeader(true, IsFloat);
-}
-
-Wave64Writer::~Wave64Writer() {
-	WriteHeader(false, IsFloat);
-	WavFile.close();
-}
-
-void Wave64Writer::WriteHeader(bool Initial, bool IsFloat) {
-	FFMS_WAVEFORMATEX WFEX;
-	if (IsFloat)
-		WFEX.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
-	else
-		WFEX.wFormatTag = WAVE_FORMAT_PCM;
-	WFEX.nChannels = Channels;
-	WFEX.nSamplesPerSec = SamplesPerSec;
-	WFEX.nAvgBytesPerSec = (BitsPerSample * Channels * SamplesPerSec) / 8;
-	WFEX.nBlockAlign = (BitsPerSample * Channels) / 8;
-	WFEX.wBitsPerSample = BitsPerSample;
-	WFEX.cbSize = 0;
-
-	uint64_t Header[14];
-
-	memset(Header, 0, sizeof(Header));
-
-	memcpy(Header + 0, GuidRIFF, 16);
-	if (Initial) {
-		Header[2] = 0x7F00000000000000ull;
-	} else {
-		Header[2] = BytesWritten + sizeof(Header);
-	}
-
-	memcpy(Header + 3, GuidWAVE, 16);
-	memcpy(Header + 5, Guidfmt, 16);
-
-	Header[7] = 48;
-
-	memcpy(Header + 8, &WFEX, sizeof(WFEX));
-	memcpy(Header + 11, Guiddata, 16);
-
-	if (Initial)
-		Header[13] = 0x7E00000000000000ull;
-	else
-		Header[13] = BytesWritten + 24;
-
-	std::streampos CPos = WavFile.tellp();
-	WavFile.seekp(0, std::ios::beg);
-	WavFile.write(reinterpret_cast<const char *>(Header), sizeof(Header));
-	if (!Initial)
-		WavFile.seekp(CPos, std::ios::beg);
-}
-
-void Wave64Writer::WriteData(void *Data, std::streamsize Length) {
-	WavFile.write(reinterpret_cast<char *>(Data), Length);
-	BytesWritten += Length;
-}
diff --git a/aegisub/libffms/src/core/wave64writer.h b/aegisub/libffms/src/core/wave64writer.h
deleted file mode 100644
index 3a5fddf3e..000000000
--- a/aegisub/libffms/src/core/wave64writer.h
+++ /dev/null
@@ -1,57 +0,0 @@
-//  Copyright (c) 2007-2009 Fredrik Mellbin
-//
-//  Permission is hereby granted, free of charge, to any person obtaining a copy
-//  of this software and associated documentation files (the "Software"), to deal
-//  in the Software without restriction, including without limitation the rights
-//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//  copies of the Software, and to permit persons to whom the Software is
-//  furnished to do so, subject to the following conditions:
-//
-//  The above copyright notice and this permission notice shall be included in
-//  all copies or substantial portions of the Software.
-//
-//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-//  THE SOFTWARE.
-
-#ifndef WAVE64WRITER_H
-#define	WAVE64WRITER_H
-
-#include <stdint.h>
-#include <iostream>
-#include <fstream>
-#include "utils.h"
-
-// this is to avoid depending on windows.h etc.
-typedef struct FFMS_WAVEFORMATEX { 
-	uint16_t wFormatTag; 
-	uint16_t nChannels; 
-	uint32_t nSamplesPerSec; 
-	uint32_t nAvgBytesPerSec; 
-	uint16_t nBlockAlign; 
-	uint16_t wBitsPerSample; 
-	uint16_t cbSize; 
-} FFMS_WAVEFORMATEX;
-
-class Wave64Writer {
-public:
-	Wave64Writer(const char *Filename, uint16_t BitsPerSample, uint16_t Channels, uint32_t SamplesPerSec, bool IsFloat);
-	~Wave64Writer();
-	void WriteData(void *Data, std::streamsize Length);
-private:
-	ffms_fstream WavFile;
-	int32_t BitsPerSample;
-	int32_t Channels;
-	uint32_t SamplesPerSec;
-	uint64_t BytesWritten;
-	uint32_t HeaderSize;
-	bool IsFloat;
-
-	void WriteHeader(bool Initial, bool IsFloat);
-};
-
-#endif
diff --git a/aegisub/libffms/wscript b/aegisub/libffms/wscript
deleted file mode 100644
index 3dddeef0c..000000000
--- a/aegisub/libffms/wscript
+++ /dev/null
@@ -1,26 +0,0 @@
-#! /usr/bin/env python
-# encoding: utf-8
-#
-# Copyright (c) 2009, Kevin Ollivier <kollivier@aegisub.org>
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-def build(bld):
-    obj = bld.new_task_gen(
-        features = 'cc cxx cstaticlib',
-        target = 'ffmpegsource_aegisub',
-        defines = 'FFMS_EXPORTS HAVE_STRLCPY __STDC_CONSTANT_MACROS',
-        includes = 'include src/core',
-        uselib = 'FFMPEG')
-
-    obj.find_sources_in_dirs('src/core')
diff --git a/aegisub/src/Makefile b/aegisub/src/Makefile
index badeeec04..1b5890b7e 100644
--- a/aegisub/src/Makefile
+++ b/aegisub/src/Makefile
@@ -55,12 +55,12 @@ endif
 #######################
 # AUDIO / VIDEO SUPPORT
 #######################
-ifeq (yes, $(HAVE_PROVIDER_FFMPEGSOURCE))
+ifeq (yes, $(WITH_FFMS))
 SRC_OPT += audio_provider_ffmpegsource.cpp video_provider_ffmpegsource.cpp ffmpegsource_common.cpp
 audio_provider_ffmpegsource.o video_provider_ffmpegsource.o ffmpegsource_common.o: \
-	CXXFLAGS += $(CFLAGS_FFMPEGSOURCE) $(CFLAGS_LIBAVFORMAT) $(CFLAGS_LIBAVCODEC) $(CFLAGS_LIBSWSCALE) $(CFLAGS_LIBAVUTIL) $(CFLAGS_LIBPOSTPROC)
+	CXXFLAGS += $(CFLAGS_FFMS)
 ffmpegsource_common.o: CXXFLAGS += -D__STDC_FORMAT_MACROS
-LDFLAGS += $(LDFLAGS_FFMPEGSOURCE) $(LDFLAGS_LIBAVFORMAT) $(LDFLAGS_LIBAVCODEC) $(LDFLAGS_LIBSWSCALE) $(LDFLAGS_LIBAVUTIL) $(LDFLAGS_LIBPOSTPROC)
+LDFLAGS += $(LDFLAGS_FFMPEGSOURCE)
 LDFLAGS_POST += $(LDFLAGS_FFMPEGSOURCE)
 endif
 
@@ -70,8 +70,8 @@ endif
 ###########
 ifeq (yes, $(WITH_LIBASS))
 SRC_OPT += subtitles_provider_libass.cpp
-subtitles_provider_libass.o: CXXFLAGS += $(CFLAGS_LIBASS)  $(CFLAGS_ICONV)
-LDFLAGS += $(LDFLAGS_LIBASS) $(LDFLAGS_ICONV) $(LDFLAGS_FONTCONFIG)
+subtitles_provider_libass.o: CXXFLAGS += $(CFLAGS_LIBASS)
+LDFLAGS += $(LDFLAGS_LIBASS)
 LDFLAGS_POST += $(LDFLAGS_LIBASS)
 endif
 
@@ -106,7 +106,7 @@ charset_detect.o:				CXXFLAGS += -D_X86_
 font_file_lister_fontconfig.o:	CXXFLAGS += $(CFLAGS_FONTCONFIG) $(CFLAGS_FREETYPE)
 font_file_lister.o:				CXXFLAGS += $(CFLAGS_FREETYPE)
 text_file_reader.o:				CXXFLAGS += -D_X86_
-video_provider_manager.o:		CXXFLAGS += $(CFLAGS_FFMPEGSOURCE)
+video_provider_manager.o:		CXXFLAGS += $(CFLAGS_FFMS)
 
 
 # Ensure any optional source files above are added for compilation.
-- 
GitLab