diff -urN ffmpeg-3.2.1-orig/libavcodec/Makefile ffmpeg-3.2.1/libavcodec/Makefile
--- ffmpeg-3.2.1-orig/libavcodec/Makefile	2016-10-28 01:17:39 +0900
+++ ffmpeg-3.2.1/libavcodec/Makefile	2016-12-06 15:02:29 +0900
@@ -463,6 +463,7 @@
 OBJS-$(CONFIG_PRORES_AW_ENCODER)       += proresenc_anatoliy.o
 OBJS-$(CONFIG_PRORES_KS_ENCODER)       += proresenc_kostya.o proresdata.o
 OBJS-$(CONFIG_PTX_DECODER)             += ptx.o
+OBJS-$(ARCH_X86_32)                    += pv3.o w32dll.o w32dll-emu.o
 OBJS-$(CONFIG_QCELP_DECODER)           += qcelpdec.o                     \
                                           celp_filters.o acelp_vectors.o \
                                           acelp_filters.o
diff -urN ffmpeg-3.2.1-orig/libavcodec/allcodecs.c ffmpeg-3.2.1/libavcodec/allcodecs.c
--- ffmpeg-3.2.1-orig/libavcodec/allcodecs.c	2016-10-28 01:17:39 +0900
+++ ffmpeg-3.2.1/libavcodec/allcodecs.c	2016-12-06 15:02:29 +0900
@@ -289,6 +289,9 @@
     REGISTER_ENCODER(PRORES_KS,         prores_ks);
     REGISTER_DECODER(PRORES_LGPL,       prores_lgpl);
     REGISTER_DECODER(PTX,               ptx);
+#if ARCH_X86_32
+    REGISTER_DECODER(PV3,               pv3);
+#endif
     REGISTER_DECODER(QDRAW,             qdraw);
     REGISTER_DECODER(QPEG,              qpeg);
     REGISTER_ENCDEC (QTRLE,             qtrle);
diff -urN ffmpeg-3.2.1-orig/libavcodec/avcodec.h ffmpeg-3.2.1/libavcodec/avcodec.h
--- ffmpeg-3.2.1-orig/libavcodec/avcodec.h	2016-11-26 11:12:05 +0900
+++ ffmpeg-3.2.1/libavcodec/avcodec.h	2016-12-06 15:02:29 +0900
@@ -389,6 +389,8 @@
     AV_CODEC_ID_SCREENPRESSO,
     AV_CODEC_ID_RSCC,
 
+    AV_CODEC_ID_PV3VIDEO,
+
     AV_CODEC_ID_Y41P = 0x8000,
     AV_CODEC_ID_AVRP,
     AV_CODEC_ID_012V,
diff -urN ffmpeg-3.2.1-orig/libavcodec/codec_desc.c ffmpeg-3.2.1/libavcodec/codec_desc.c
--- ffmpeg-3.2.1-orig/libavcodec/codec_desc.c	2016-10-28 01:17:39 +0900
+++ ffmpeg-3.2.1/libavcodec/codec_desc.c	2016-12-06 15:02:29 +0900
@@ -1197,6 +1197,13 @@
         .name      = "smvjpeg",
         .long_name = NULL_IF_CONFIG_SMALL("Sigmatel Motion Video"),
     },
+    {
+        .id        = AV_CODEC_ID_PV3VIDEO,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "pv3video",
+        .long_name = NULL_IF_CONFIG_SMALL("Earth Soft PV3 video"),
+        .props     = AV_CODEC_PROP_LOSSY,
+    },
 
     {
         .id        = AV_CODEC_ID_G2M,
diff -urN ffmpeg-3.2.1-orig/libavcodec/pv3.c ffmpeg-3.2.1/libavcodec/pv3.c
--- ffmpeg-3.2.1-orig/libavcodec/pv3.c	1970-01-01 09:00:00 +0900
+++ ffmpeg-3.2.1/libavcodec/pv3.c	2016-12-06 15:02:29 +0900
@@ -0,0 +1,298 @@
+/*
+ * Earth Soft PV3 video decoder
+ * Copyright (c) 2015 Andrew Church (achurch@achurch.org)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Earth Soft PV3 video decoder
+ *
+ * Technical details (in Japanese):
+ *    http://earthsoft.jp/PV/tech-file.html
+ *    http://earthsoft.jp/PV/tech-codec.html
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+#include "w32dll.h"
+
+#include "libavutil/opt.h"
+#include "libavutil/intreadwrite.h"
+
+/* Parameter structures used by dv.dll decode functions */
+typedef struct PV3InputFrameParams {
+    uint8_t w_8;            ///< width / 8
+    uint8_t h_8;            ///< height / 8
+    uint16_t unknown1;
+    uint32_t unknown2;
+    uint32_t progressive;
+} PV3InputFrameParams;
+typedef struct PV3OutputFrameParams {
+    uint32_t stride;
+    /* void * */ uint32_t outbuf;
+} PV3OutputFrameParams;
+typedef struct PV3VideoDecodeParams {
+    uint32_t datasets;      ///< Bit mask of data sets (0-3) to process
+    /* void * */ uint32_t workbuf;  ///< Work buffer of at least 0x424? bytes
+    /* PV3InputFrameParams * */ uint32_t in_params;
+    /* const void ** */ uint32_t frameptr;  ///< Pointer to input frame
+    /* PV3OutputFrameParams * */ uint32_t out_params;
+} PV3VideoDecodeParams;
+typedef struct PV3AudioParams {
+    uint32_t rate;          ///< Sampling rate
+    uint32_t pad04;
+    uint64_t frame_index;   ///< Index of first audio frame (file start = 0)
+    uint32_t frame_count;   ///< Number of audio frames for this video frame
+    uint32_t pad14;
+    /* void * */ uint32_t audiobuf;
+    uint32_t pad1C;
+} PV3AudioParams;
+typedef struct PV3AudioEncodedParams {
+    uint32_t unknown;
+    void *frame;            ///< Encoded frame
+} PV3AudioEncodedParams;
+
+/* Handle structures used by dv.dll */
+typedef struct PV3VideoFuncs {
+    uint32_t func0;
+    uint32_t func1;
+    uint32_t func2;
+    uint32_t func3;
+    uint32_t func4;
+    uint32_t func5;
+    uint32_t func6;
+    /* "unknown" here points to at least 0x500 bytes of memory */
+    /* void (*decode_init)(void *unknown, const uint16_t *quantizers); */
+    uint32_t decode_init;
+    /* void (*decode)(PV3VideoDecodeParams *params); */
+    uint32_t decode;
+} PV3VideoFuncs;
+typedef struct PV3VideoHandle {
+    /* PV3VideoFuncs * */ uint32_t funcs;
+} PV3VideoHandle;
+typedef struct PV3AudioFuncs {
+    /* void (*encode)(PV3AudioParams *in,
+                      PV3AudioEncodedParams *out); */
+    uint32_t encode;
+    /* void (*decode)(PV3AudioEncodedParams *in,
+                      PV3AudioParams *out); */
+    uint32_t decode;
+} PV3AudioFuncs;
+typedef struct PV3AudioHandle {
+    /* PV3AudioFuncs * */ uint32_t funcs;
+} PV3AudioHandle;
+typedef struct PV3CodecFuncs {
+    /* int (*init)(int a, int b); */
+    uint32_t init;
+    /* int (*fini)(void); */
+    uint32_t fini;
+    /* PV3VideoHandle *(*get_video_handle)(void); */
+    uint32_t get_video_handle;
+    /* PV3AudioHandle *(*get_audio_handle)(void); */
+    uint32_t get_audio_handle;
+} PV3CodecFuncs;
+typedef struct PV3CodecHandle {
+    /* PV3CodecFuncs * */ uint32_t funcs;
+} PV3CodecHandle;
+
+typedef struct PV3DecodeContext {
+    AVClass *class;
+
+    char *dv_dll_path;      ///< Path of PV3 dv.dll (private option)
+    W32DLLHandle dv_dll;    ///< dv.dll handle
+    PV3CodecHandle *codec_handle;
+    PV3CodecFuncs *codec_funcs;
+    PV3VideoHandle *video_handle;
+    PV3VideoFuncs *video_funcs;
+
+    uint8_t work_mem[0x800];  ///< Used by dv.dll
+} PV3DecodeContext;
+
+
+static intptr_t pv3_call(const void *handle, uint32_t func, ...)
+{
+    va_list args;
+    intptr_t arg1, arg2, retval;
+
+    va_start(args, func);
+    arg1 = va_arg(args, intptr_t);
+    arg2 = va_arg(args, intptr_t);
+    va_end(args);
+
+#if ARCH_X86_32
+    __asm__("mov %%esp, %%edi;" // Since the DLL uses the __stdcall calling
+            "push %%esi;"       // convention, it will pop the "correct" number
+            "push %%edx;"       // of arguments off the stack when it returns.
+            "call *%%ebx;"      // Explicitly save and restore the stack pointer
+            "mov %%edi, %%esp;" // to make sure we get the right value back.
+            : "=a" (retval)
+            : "b" (func), "c" (handle), "d" (arg1), "S" (arg2)
+            : "edi", "cc", "memory");
+#else
+    retval = -1;
+#endif
+
+    return retval;
+}
+
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+    PV3DecodeContext * const pv3 = avctx->priv_data;
+    void *(*entry)(void);
+
+    pv3->dv_dll = 0;
+    pv3->codec_handle = NULL;
+    pv3->video_handle = NULL;
+
+    if (!avctx->extradata) {
+        av_log(avctx, AV_LOG_ERROR, "Quantizer data not supplied\n");
+        return -1;
+    } else if (avctx->extradata_size < 256) {
+        av_log(avctx, AV_LOG_ERROR, "Quantizer data too small (%d, should be"
+               " 256)\n", avctx->extradata_size);
+        return 1;
+    }
+
+#if ARCH_X86_32
+    if (!pv3->dv_dll_path) {
+        av_log(avctx, AV_LOG_ERROR,
+               "No dv.dll path specified (use dv_dll option)\n");
+        return -1;
+    }
+
+    if (!(pv3->dv_dll = w32dll_load(pv3->dv_dll_path, 1))) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot load %s: %s", pv3->dv_dll_path,
+               errno==ENOEXEC ? "Not a valid Win32 DLL file" :
+               errno==ETXTBSY ? "DLL initialization failed" : strerror(errno));
+        return -1;
+    }
+
+    entry = w32dll_lookup_by_name(pv3->dv_dll, "_");
+    if (!entry) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot find dv.dll entry point\n");
+        w32dll_unload(pv3->dv_dll);
+        return -1;
+    }
+
+    pv3->codec_handle = (*entry)();
+    if (!pv3->codec_handle) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to initialize dv.dll\n");
+        w32dll_unload(pv3->dv_dll);
+        return -1;
+    }
+    pv3->codec_funcs = (PV3CodecFuncs *)(uintptr_t)pv3->codec_handle->funcs;
+
+    pv3_call(pv3->codec_handle, pv3->codec_funcs->init, 4, 122); //magic numbers
+    pv3->video_handle = (void *)pv3_call(
+        pv3->codec_handle, pv3->codec_funcs->get_video_handle);
+    if (!pv3->video_handle) {
+        av_log(avctx, AV_LOG_ERROR, "Unable to retrieve decoder handle\n");
+        pv3_call(pv3->codec_handle, pv3->codec_funcs->fini);
+        w32dll_unload(pv3->dv_dll);
+        return 0;
+    }
+    pv3->video_funcs = (PV3VideoFuncs *)(uintptr_t)pv3->video_handle->funcs;
+
+    pv3_call(pv3->video_handle, pv3->video_funcs->decode_init,
+             (uintptr_t)pv3->work_mem, (uintptr_t)avctx->extradata);
+
+    return 0;
+#else  // !ARCH_X86_32
+    av_log(avctx, AV_LOG_ERROR, "Not supported on this OS/architecture\n");
+    return -1;
+#endif
+}
+
+static av_cold int decode_close(AVCodecContext *avctx)
+{
+    PV3DecodeContext * const pv3 = avctx->priv_data;
+
+#if ARCH_X86_32
+    pv3_call(pv3->codec_handle, pv3->codec_funcs->fini);
+    w32dll_unload(pv3->dv_dll);
+#endif
+    return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *pkt)
+{
+    PV3DecodeContext * const pv3 = avctx->priv_data;
+    AVFrame *frame = data;
+    int ret;
+
+    PV3InputFrameParams in_params;
+    PV3OutputFrameParams out_params;
+    PV3VideoDecodeParams decode_params;
+    int i;
+
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+        return ret;
+
+    memset(&in_params, 0, sizeof(in_params));
+    in_params.w_8 = avctx->width/8;
+    in_params.h_8 = avctx->height/8;
+    in_params.progressive = (avctx->field_order == AV_FIELD_PROGRESSIVE);
+    memset(&out_params, 0, sizeof(out_params));
+    out_params.stride = frame->linesize[0];
+    out_params.outbuf = (uintptr_t)frame->data[0];
+    memset(&decode_params, 0, sizeof(decode_params));
+
+    /* Process each set of data */
+    decode_params.workbuf = (uintptr_t)pv3->work_mem;
+    decode_params.in_params = (uintptr_t)&in_params;
+    decode_params.frameptr = (uintptr_t)&pkt->data;
+    decode_params.out_params = (uintptr_t)&out_params;
+    for (i = 0; i < (in_params.progressive ? 2 : 4); i++) {
+        decode_params.datasets = 1<<i;
+        if (pv3_call(pv3->video_handle, pv3->video_funcs->decode,
+                     &decode_params) < 0) {
+            return -1;
+        }
+    }
+
+    *got_frame = 1;
+    return 0;
+}
+
+static const AVOption options[] = {
+    { "dv_dll", "Path of dv.dll", offsetof(PV3DecodeContext, dv_dll_path),
+      AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0,
+      AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM },
+    { NULL }
+};
+
+static const AVClass pv3_decoder_class = {
+    .class_name = "PV3 decoder",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_pv3_decoder = {
+    .name           = "pv3",
+    .long_name      = NULL_IF_CONFIG_SMALL("Earth Soft PV3"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_PV3VIDEO,
+    .priv_data_size = sizeof(PV3DecodeContext),
+    .priv_class     = &pv3_decoder_class,
+    .init           = decode_init,
+    .decode         = decode_frame,
+    .close          = decode_close,
+    .capabilities   = CODEC_CAP_DR1,
+};
diff -urN ffmpeg-3.2.1-orig/libavcodec/w32dll-emu.c ffmpeg-3.2.1/libavcodec/w32dll-emu.c
--- ffmpeg-3.2.1-orig/libavcodec/w32dll-emu.c	1970-01-01 09:00:00 +0900
+++ ffmpeg-3.2.1/libavcodec/w32dll-emu.c	2016-12-06 15:09:42 +0900
@@ -0,0 +1,1303 @@
+/*
+ * w32dll-emu.c -- Win32 emulation routines to support DLLs
+ * Written by Andrew Church <achurch@achurch.org>
+ *
+ * This file is part of transcode, a video stream processing tool.
+ * transcode is free software, distributable under the terms of the GNU
+ * General Public License (version 2 or later).  See the file COPYING
+ * for details.
+ */
+
+#include "config.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <wchar.h>
+
+#include "w32dll.h"
+#include "w32dll-local.h"
+#include "w32dll-emu.h"
+
+#if !defined(__linux__)
+# error Sorry, only implemented on Linux.
+#endif
+#if !ARCH_X86
+# error Sorry, this requires an x86 architecture.
+#endif
+
+#define GETPAGESIZE() (sysconf(_SC_PAGESIZE))
+
+/* not declared by <string.h>... what is this I don't even */
+extern int strcasecmp(const char *a, const char *b);
+
+/*************************************************************************/
+
+/* Define this to enable creation of stubs for unemulated functions that
+ * print a warning to stderr and return -1 when the function is called.
+ * Note that this leaks one page of mmap() memory plus string memory per
+ * stub created.  (Note, however, that for WINAPI functions the debug stub
+ * cannot know how many arguments to pop, so the program will probably
+ * crash on return.)
+ * Defining this also enables some debugging messages to stderr.
+ */
+
+//#define W32DLL_EMU_DEBUG
+
+/*************************************************************************/
+
+/* Array of known modules and associated handles (see w32dll-emu.h),
+ * terminated with name==NULL. */
+
+#define MOD(modname) {.name = #modname ".dll", .handle = HANDLE_##modname}
+
+static const struct {
+    const char *name;
+    uint32_t handle;
+} emumods[] = {
+    MOD(KERNEL32),
+    MOD(USER32),
+    { .name = NULL }
+};
+
+#undef MOD
+
+
+/* Array of emulated functions, terminated with module==0. */
+
+#define FUNC(mod,func) \
+    {.module = HANDLE_##mod, .ordinal = 0, .name = #func, .funcptr = func}
+
+static const struct {
+    uint32_t module;  /* handle */
+    uint32_t ordinal;
+    const char *name;
+    void *funcptr;
+} emufuncs[] = {
+    FUNC(KERNEL32, CloseHandle),
+    FUNC(KERNEL32, CreateSemaphoreA),
+    FUNC(KERNEL32, CreateSemaphoreW),
+    FUNC(KERNEL32, DeleteCriticalSection),
+    FUNC(KERNEL32, EnterCriticalSection),
+    FUNC(KERNEL32, ExitProcess),
+    FUNC(KERNEL32, FreeEnvironmentStringsA),
+    FUNC(KERNEL32, FreeEnvironmentStringsW),
+    FUNC(KERNEL32, GetACP),
+    FUNC(KERNEL32, GetCPInfo),
+    FUNC(KERNEL32, GetCommandLineA),
+    FUNC(KERNEL32, GetConsoleMode),
+    FUNC(KERNEL32, GetCurrentProcessId),
+    FUNC(KERNEL32, GetCurrentThreadId),
+    FUNC(KERNEL32, GetEnvironmentStringsA),
+    FUNC(KERNEL32, GetEnvironmentStringsW),
+    FUNC(KERNEL32, GetFileType),
+    FUNC(KERNEL32, GetLastError),
+    FUNC(KERNEL32, GetModuleFileNameA),
+    FUNC(KERNEL32, GetModuleHandleA),
+    FUNC(KERNEL32, GetProcAddress),
+    FUNC(KERNEL32, GetProcessHeap),
+    FUNC(KERNEL32, GetStartupInfoA),
+    FUNC(KERNEL32, GetStdHandle),
+    FUNC(KERNEL32, GetStringTypeW),
+    FUNC(KERNEL32, GetSystemTimeAsFileTime),
+    FUNC(KERNEL32, GetTickCount),
+    FUNC(KERNEL32, GetVersionExA),
+    FUNC(KERNEL32, HeapAlloc),
+    FUNC(KERNEL32, HeapCreate),
+    FUNC(KERNEL32, HeapDestroy),
+    FUNC(KERNEL32, HeapFree),
+    FUNC(KERNEL32, HeapReAlloc),
+    FUNC(KERNEL32, HeapSize),
+    FUNC(KERNEL32, InitializeCriticalSection),
+    FUNC(KERNEL32, InterlockedCompareExchange),
+    FUNC(KERNEL32, InterlockedCompareExchangePointer),
+    FUNC(KERNEL32, InterlockedDecrement),
+    FUNC(KERNEL32, InterlockedExchange),
+    FUNC(KERNEL32, InterlockedExchangeAdd),
+    FUNC(KERNEL32, InterlockedExchangePointer),
+    FUNC(KERNEL32, InterlockedIncrement),
+    FUNC(KERNEL32, InterlockedTestExchange),
+    FUNC(KERNEL32, LCMapStringA),
+    FUNC(KERNEL32, LCMapStringW),
+    FUNC(KERNEL32, LeaveCriticalSection),
+    FUNC(KERNEL32, LoadLibraryA),
+    FUNC(KERNEL32, MultiByteToWideChar),
+    FUNC(KERNEL32, QueryPerformanceCounter),
+    FUNC(KERNEL32, ReleaseSemaphore),
+    FUNC(KERNEL32, SetHandleCount),
+    FUNC(KERNEL32, SetLastError),
+    FUNC(KERNEL32, TlsAlloc),
+    FUNC(KERNEL32, TlsFree),
+    FUNC(KERNEL32, TlsGetValue),
+    FUNC(KERNEL32, TlsSetValue),
+    FUNC(KERNEL32, WaitForSingleObject),
+    FUNC(KERNEL32, WideCharToMultiByte),
+    FUNC(KERNEL32, WriteFile),
+
+    FUNC(USER32, GetActiveWindow),
+    FUNC(USER32, MessageBoxA),
+    FUNC(USER32, MessageBoxW),
+
+    { .module = 0 }
+};
+
+#undef FUNC
+
+
+/* Debugging functions. */
+
+#if defined(W32DLL_EMU_DEBUG)
+# if !defined(MAP_ANONYMOUS)
+#  warn MAP_ANONYMOUS not defined, disabling W32DLL_EMU_DEBUG
+#  undef W32DLL_EMU_DEBUG
+# else
+static int32_t debug_stub(const char *module, const char *name,
+                          uint32_t ordinal);
+static void *create_debug_stub(const char *module, const char *name,
+                               uint32_t ordinal);
+# endif
+#endif
+
+#if defined(W32DLL_EMU_DEBUG)
+# define D(x) x
+#else
+# define D(x) /*nothing*/
+#endif
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* External interface. */
+
+/*************************************************************************/
+
+/**
+ * w32dll_emu_import_by_name, w32dll_emu_import_by_ordinal:  Return the
+ * address of the emulated function corresponding to the given import,
+ * selected by either name or ordinal.
+ *
+ * Parameters:
+ *      module: Name of the module from which to import.
+ *        name: Import name descriptor (w32dll_emu_import_by_name() only).
+ *     ordinal: Import ordinal (w32dll_emu_import_by_ordinal() only).
+ * Return value:
+ *     The address corresponding to the import, or NULL if no emulation
+ *     is available for the import.
+ */
+
+void *w32dll_emu_import_by_name(const char *module,
+                                const struct import_name_entry *name)
+{
+    int i;
+    uint32_t handle = 0;
+
+    for (i = 0; emumods[i].name != NULL; i++) {
+        if (strcasecmp(emumods[i].name, module) == 0) {
+            handle = emumods[i].handle;
+            break;
+        }
+    }
+    if (handle) {
+        for (i = 0; emufuncs[i].module != 0; i++) {
+            if (emufuncs[i].module == handle
+             && strcasecmp(emufuncs[i].name, name->name) == 0)
+                return emufuncs[i].funcptr;
+        }
+    }
+#if defined(W32DLL_EMU_DEBUG)
+    return create_debug_stub(module, name->name, 0);
+#else
+    return NULL;
+#endif
+}
+
+/************************************/
+
+void *w32dll_emu_import_by_ordinal(const char *module, uint32_t ordinal)
+{
+    /* Not supported yet. */
+#if defined(W32DLL_EMU_DEBUG)
+    return create_debug_stub(module, NULL, ordinal);
+#else
+    return NULL;
+#endif
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* The remainder of the file consists of emulation functions. */
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Emulation debugging functions. */
+
+#if defined(W32DLL_EMU_DEBUG)
+
+/*************************************************************************/
+
+/**
+ * debug_stub:  Stub function which prints an error message.  Called by
+ * machine code generated by create_debug_stub().
+ *
+ * Parameters:
+ *      module: Module name for which the stub is being called.
+ *        name: Function name for which the stub is being called, or NULL
+ *              if not applicable.
+ *     ordinal: Function ordinal for which the stub is being called, if
+ *              applicable.
+ * Return value:
+ *     Always returns -1.
+ */
+
+static int32_t debug_stub(const char *module, const char *name,
+                          uint32_t ordinal)
+{
+    char numbuf[16];
+    snprintf(numbuf, sizeof(numbuf), "0x%08X", ordinal);
+    fprintf(stderr, "[w32dll-emu] Unsupported function: %s/%s\n",
+            module, name ? name : numbuf);
+    return -1;
+}
+
+/*************************************************************************/
+
+/**
+ * create_debug_stub:  Create a function which calls debug_stub().
+ *
+ * Parameters:
+ *      module: Module name for which the stub is being created.
+ *        name: Function name for which the stub is being created, or NULL
+ *              if not applicable.
+ *     ordinal: Function ordinal for which the stub is being created, if
+ *              applicable.
+ * Return value:
+ *     A pointer to the newly-created debug stub, or NULL on error.
+ */
+
+static void *create_debug_stub(const char *module, const char *name,
+                               uint32_t ordinal)
+{
+    char *funcpage, *s;
+    int32_t offset;
+
+    funcpage = mmap(NULL, GETPAGESIZE(), PROT_READ | PROT_WRITE | PROT_EXEC,
+                    MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
+    if (funcpage == MAP_FAILED)
+        return NULL;
+
+    if (module)
+        module = strdup(module);
+    if (!module)
+        module = "(null)";
+    if (name) {
+        name = strdup(name);
+        if (!name)
+            name = "(null)";
+    }
+
+    /* Create the function.  The code below is the equivalent of the
+     * following assembly:
+     *     pop %eax
+     *     pushl ordinal
+     *     pushl name
+     *     pushl module
+     *     push %eax
+     *     jmp debug_stub
+     */
+    strcpy(funcpage, "\x58"
+                     "\x68\x11\x11\x11\x11"
+                     "\x68\x22\x22\x22\x22"
+                     "\x68\x33\x33\x33\x33"
+                     "\x50"
+                     "\xE9\x44\x44\x44\x44");
+    /* Fill in the various values.  Do them in reverse order to avoid
+     * strstr() getting confused by intermediate nulls! */
+    s = strstr(funcpage,"\x44\x44\x44\x44");
+    offset = (int32_t)debug_stub - (int32_t)(s+4);
+    memcpy(s, &offset, 4);
+    memcpy(strstr(funcpage,"\x33\x33\x33\x33"), &module, 4);
+    memcpy(strstr(funcpage,"\x22\x22\x22\x22"), &name, 4);
+    memcpy(strstr(funcpage,"\x11\x11\x11\x11"), &ordinal, 4);
+
+    /* Return the new page. */
+    return funcpage;
+}
+
+#endif  /* W32DLL_EMU_DEBUG */
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Emulated functions in alphabetical order.  See the Windows documentation
+ * for details about each function. */
+
+/*************************************************************************/
+
+/* Various data. */
+
+static uint32_t w32_errno = 0;  /* for GetLastError() */
+static int tls_alloced[TLS_MINIMUM_AVAILABLE];
+static void *tls_data[TLS_MINIMUM_AVAILABLE];
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* KERNEL32 functions */
+
+/*************************************************************************/
+
+static WINAPI int CloseHandle(uint32_t handle)
+{
+    return 1;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t CreateSemaphoreA(void *attr, uint32_t initial,
+                                        uint32_t max, const char *name)
+{
+    return HANDLE_SEMAPHORE;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t CreateSemaphoreW(void *attr, uint32_t initial,
+                                        uint32_t max, const uint16_t *name)
+{
+    return HANDLE_SEMAPHORE;
+}
+
+/*************************************************************************/
+
+static WINAPI void DeleteCriticalSection(void *lock)
+{
+    /* Win32 "critical sections" are basically locks shared between threads.
+     * We only deal with one thread at the moment, so we ignore all these. */
+}
+
+/*************************************************************************/
+
+static WINAPI void EnterCriticalSection(void *lock)
+{
+}
+
+/*************************************************************************/
+
+static WINAPI void ExitProcess(unsigned int exitcode)
+{
+    D((fprintf(stderr, "ExitProcess(%u) called, exiting...\n", exitcode)));
+    exit(exitcode);
+}
+
+/*************************************************************************/
+
+static WINAPI int FreeEnvironmentStringsA(void *env)
+{
+    return 1;
+}
+
+/*************************************************************************/
+
+static WINAPI int FreeEnvironmentStringsW(void *env)
+{
+    return 1;
+}
+
+/*************************************************************************/
+
+static WINAPI unsigned int GetACP(void)
+{
+    return 0;
+}
+
+/*************************************************************************/
+
+static WINAPI int GetCPInfo(unsigned int codepage, CPINFO *result)
+{
+    if (!result) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    result->maxbytes = 1;
+    result->defchar[0] = '?';
+    result->defchar[1] = 0;
+    memset(result->leadbytes, 0, sizeof(result->leadbytes));
+    return 1;
+}
+
+/*************************************************************************/
+
+static WINAPI char *GetCommandLineA(void)
+{
+    static char dummy_cmdline[] = "dummy.exe";
+    return dummy_cmdline;
+}
+
+/*************************************************************************/
+
+static WINAPI int GetConsoleMode(uint32_t file, uint16_t *result)
+{
+    if (file == HANDLE_STDIN) {
+        *result = 0x0007;  /* PROCESSED_INPUT | LINE_INPUT | ECHO_INPUT */
+    } else if (file == HANDLE_STDOUT) {
+        *result = 0x0001;  /* PROCESSED_OUTPUT -- but not really!  oh well */
+    } else if (file == HANDLE_STDERR) {
+        *result = 0x0000;
+    } else {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return 0;
+    }
+    return 1;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t GetCurrentProcessId(void)
+{
+    return getpid();
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t GetCurrentThreadId(void)
+{
+    return getpid();
+}
+
+/*************************************************************************/
+
+static WINAPI void *GetEnvironmentStringsA(void)
+{
+    static char dummy_environ[2] = "\0\0";
+    return dummy_environ;
+}
+
+/*************************************************************************/
+
+static WINAPI void *GetEnvironmentStringsW(void)
+{
+    static uint16_t dummy_environ[2] = {0,0};
+    return dummy_environ;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t GetFileType(uint32_t file)
+{
+    SetLastError(NO_ERROR);
+    if (file==HANDLE_STDIN || file==HANDLE_STDOUT || file==HANDLE_STDERR)
+        return 2;  /* FILE_TYPE_CHAR */
+    SetLastError(ERROR_INVALID_HANDLE);
+    return 0;  /* FILE_TYPE_UNKNOWN */
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t GetLastError(void)
+{
+    return w32_errno;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t GetModuleFileNameA(uint32_t module, char *buf,
+                                          uint32_t size)
+{
+    int n = -1;
+
+    if (module == 0 && module == HANDLE_DEFAULT) {
+        n = snprintf(buf, size, "%s", "dummy.exe");
+    } else {
+        int i;
+        for (i = 0; emumods[i].name != NULL; i++) {
+            if (emumods[i].handle == module) {
+                n = snprintf(buf, size, "%s", emumods[i].name);
+                break;
+            }
+        }
+        if (!emumods[i].name) {
+            SetLastError(ERROR_INVALID_HANDLE);
+            return 0;
+        }
+    }
+    if (n < 0 || n >= size) {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        return 0;
+    }
+    return n;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t GetModuleHandleA(const char *name)
+{
+    int i;
+
+    if (!name)
+        return HANDLE_DEFAULT;
+    for (i = 0; emumods[i].name != NULL; i++) {
+        if (strcasecmp(emumods[i].name, name) == 0)
+            return emumods[i].handle;
+    }
+    D((fprintf(stderr, "GetModuleHandleA(%s) -> 0\n", name)));
+    SetLastError(ERROR_FILE_NOT_FOUND);
+    return 0;
+}
+
+/*************************************************************************/
+
+static WINAPI FARPROC GetProcAddress(uint32_t module, const char *name)
+{
+    int i;
+
+    if (!name) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return NULL;
+    }
+    if (module == 0 && module == HANDLE_DEFAULT) {
+        D((fprintf(stderr, "GetProcAddress(DEFAULT, %s) -> NULL\n", name)));
+        SetLastError(ERROR_INVALID_FUNCTION);
+        return NULL;
+    }
+    for (i = 0; emufuncs[i].module != 0; i++) {
+        if (emufuncs[i].module==module && strcasecmp(emufuncs[i].name,name)==0)
+            return emufuncs[i].funcptr;
+    }
+    D((fprintf(stderr, "GetProcAddress(%d, %s) -> NULL\n", module, name)));
+    SetLastError(ERROR_INVALID_HANDLE);
+    return NULL;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t GetProcessHeap(void)
+{
+    return HANDLE_HEAP;
+}
+
+/*************************************************************************/
+
+static WINAPI void GetStartupInfoA(STARTUPINFO *result)
+{
+    result->size = sizeof(*result);
+    result->reserved = NULL;
+    result->desktop = NULL;
+    result->title = "dummy";
+    result->x = 0;
+    result->y = 0;
+    result->w = 640;
+    result->h = 480;
+    result->wchars = 80;
+    result->hchars = 30;
+    result->fill = 0;
+    result->flags = 0;
+    result->show = 1;
+    result->reserved2 = 0;
+    result->reserved3 = NULL;
+    result->h_stdin = HANDLE_STDIN;
+    result->h_stdout = HANDLE_STDOUT;
+    result->h_stderr = HANDLE_STDERR;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t GetStdHandle(uint32_t index)
+{
+    if (index == (uint32_t)-10)
+        return HANDLE_STDIN;
+    if (index == (uint32_t)-11)
+        return HANDLE_STDOUT;
+    if (index == (uint32_t)-12)
+        return HANDLE_STDERR;
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return INVALID_HANDLE_VALUE;
+}
+
+/*************************************************************************/
+
+static WINAPI int GetStringTypeW(uint32_t type, const uint16_t *str,
+                                 int len, uint16_t *typebuf)
+{
+    int i;
+
+    if (!str || len <= 0 || !typebuf) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    for (i = 0; i < len; i++) {
+        switch (type) {
+          case 1:
+            typebuf[i] = 0;
+            if (str[i] <= 0x7F) {
+                if (isupper((char)str[i]))
+                    typebuf[i] |= 0x0001;
+                if (islower((char)str[i]))
+                    typebuf[i] |= 0x0002;
+                if (isdigit((char)str[i]))
+                    typebuf[i] |= 0x0004;
+                if (isspace((char)str[i]))
+                    typebuf[i] |= 0x0008;
+                if (ispunct((char)str[i]))
+                    typebuf[i] |= 0x0010;
+                if (iscntrl((char)str[i]))
+                    typebuf[i] |= 0x0020;
+                if (isxdigit((char)str[i]))
+                    typebuf[i] |= 0x0080;
+                if (isalpha((char)str[i]))
+                    typebuf[i] |= 0x0100;
+            }  // if (str[i] <= 0x7F)
+            break;
+          case 2:
+            if (str[i] >= 0x20 && str[i] <= 0x7E) {
+                typebuf[i] = 1;
+            } else {
+                typebuf[i] = 0;
+            }
+            break;
+          case 3:
+            if (isalpha((char)str[i])) {
+                typebuf[i] = 0x8040;  /* ALPHA | HALFWIDTH */
+            }
+            break;
+        }
+    }
+    return 1;
+}
+
+/*************************************************************************/
+
+static WINAPI void GetSystemTimeAsFileTime(uint64_t *result)
+{
+    /* Time is in 100-nanosecond units since 1601/1/1 0:00 UTC */
+    /* Difference from 1601/1/1 to 1970/1/1 = 369 years, incl. 89 leap years */
+    *result = ((uint64_t)time(NULL) + (uint64_t)(369*365+89)*86400) * 10000000;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t GetTickCount(void)
+{
+    struct timeval tv;
+#if defined(HAVE_GETTIMEOFDAY)
+    gettimeofday(&tv, NULL);
+#else
+    tv.tv_sec = time(NULL);
+    tv.tv_usec = 0;
+#endif
+    return tv.tv_sec*1000 + tv.tv_usec/1000;  // as good as anything else
+}
+
+/*************************************************************************/
+
+static WINAPI int GetVersionExA(OSVERSIONINFOEX *result)
+{
+    if (!result || result->size < 148) {  // 148: sizeof(OSVERSIONINFO)
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    /* Emulate Windows 2000 */
+    result->major = 5;
+    result->minor = 0;
+    result->build = 31337;
+    result->platform = 2;
+    memset(result->extra, 0, sizeof(result->extra));
+    if (result->size >= sizeof(*result)) {
+        result->sp_major = 4;
+        result->sp_minor = 0;
+        result->suite = 0x0000;
+        result->type = 0x01;
+        result->reserved = 0;
+    }
+    return 1;
+}
+
+/*************************************************************************/
+
+#define HEAPALLOC_MAGIC 0x9D1A9DA1
+#define HEAPFREE_MAGIC (~HEAPALLOC_MAGIC)
+
+static WINAPI void *HeapAlloc(uint32_t heap, uint32_t flags, size_t size)
+{
+    void *ptr = malloc(size+8);
+    D((fprintf(stderr, "HeapAlloc(%u) -> %p%s", size, ptr, ptr ? "" : "\n")));
+    if (!ptr) {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return NULL;
+    }
+    ptr = (uint32_t *)ptr+2;
+    ((uint32_t *)ptr)[-2] = HEAPALLOC_MAGIC;
+    ((uint32_t *)ptr)[-1] = size;
+    D((fprintf(stderr, " -> %p\n", ptr)));
+    if (flags & 0x00000008)  /* HEAP_ZERO_MEMORY */
+        memset(ptr, 0, size);
+    return ptr;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t HeapCreate(uint32_t flags, size_t initial, size_t max)
+{
+    /* Just share the same "heap" */
+    return HANDLE_HEAP;
+}
+
+/*************************************************************************/
+
+static WINAPI int HeapDestroy(uint32_t heap)
+{
+    return 1;  /* Ignore */
+}
+
+/*************************************************************************/
+
+static WINAPI int HeapFree(uint32_t heap, uint32_t flags, void *ptr)
+{
+    D((fprintf(stderr, "HeapFree(%p) [%08X %u]\n", ptr,
+               ptr ? ((uint32_t *)ptr)[-2] : 0,
+               ptr ? ((uint32_t *)ptr)[-1] : 0)));
+    if (ptr) {
+        if (((uint32_t *)ptr)[-2] != HEAPALLOC_MAGIC) {
+            D((fprintf(stderr, "HeapFree() on %s pointer %p!\n",
+                       ((uint32_t *)ptr)[-2]==HEAPFREE_MAGIC ? "freed" : "bad",
+                       ptr)));
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return 0;
+        }
+        ((uint32_t *)ptr)[-1] = HEAPFREE_MAGIC;
+        free((uint32_t *)ptr-2);
+    }
+    return 1;
+}
+
+/*************************************************************************/
+
+static WINAPI void *HeapReAlloc(uint32_t heap, uint32_t flags, void *ptr,
+                                size_t size)
+{
+    size_t oldsize;
+
+    D((fprintf(stderr, "HeapReAlloc(%p,%u) -> ", ptr, size)));
+    if (!ptr)
+        return HeapAlloc(heap, flags, size);
+    if (((uint32_t *)ptr)[-2] != HEAPALLOC_MAGIC) {
+        D((fprintf(stderr, "HeapReAlloc() on %s pointer %p!\n",
+                   ((uint32_t *)ptr)[-2]==HEAPFREE_MAGIC ? "freed" : "bad",
+                   ptr)));
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    oldsize = ((uint32_t *)ptr)[-1];
+    ptr = realloc((uint32_t *)ptr-2, size+8);
+    D((fprintf(stderr, "oldsize %u -> %p%s", oldsize, ptr, ptr ? "" : "\n")));
+    if (!ptr) {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return NULL;
+    }
+    ptr = (uint32_t *)ptr+2;
+    ((uint32_t *)ptr)[-2] = HEAPALLOC_MAGIC;
+    ((uint32_t *)ptr)[-1] = size;
+    D((fprintf(stderr, " -> %p\n", ptr)));
+    if (size > oldsize && (flags & 0x00000008))  /* HEAP_ZERO_MEMORY */
+        memset((uint8_t *)ptr + oldsize, 0, size - oldsize);
+    return ptr;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t HeapSize(uint32_t heap, uint32_t flags, const void *ptr)
+{
+    D((fprintf(stderr, "HeapSize(%p) -> %u\n", ptr,
+               (uint32_t) (((const uint64_t *)ptr)[-1]))));
+    return (uint32_t) (((const uint64_t *)ptr)[-1]);
+}
+
+/*************************************************************************/
+
+static WINAPI void InitializeCriticalSection(void *lock)
+{
+}
+
+/*************************************************************************/
+
+static WINAPI int32_t InterlockedCompareExchange
+                            (int32_t *var, int32_t testval, int32_t newval)
+{
+    int32_t oldval = *var;
+    if (oldval == testval)
+        *var = newval;
+    return oldval;
+}
+
+/*************************************************************************/
+
+static WINAPI void *InterlockedCompareExchangePointer
+                                 (void ***var, void *testval, void *newval)
+{
+    void *oldval = *var;
+    if (oldval == testval)
+        *var = newval;
+    return oldval;
+}
+
+/*************************************************************************/
+
+static WINAPI int32_t InterlockedDecrement(int32_t *var)
+{
+    return --*var;
+}
+
+/*************************************************************************/
+
+static WINAPI int32_t InterlockedExchange(int32_t *var, int32_t newval)
+{
+    int32_t oldval = *var;
+    *var = newval;
+    return oldval;
+}
+
+/*************************************************************************/
+
+static WINAPI int32_t InterlockedExchangeAdd(int32_t *var, int32_t addval)
+{
+    int32_t oldval = *var;
+    *var += addval;
+    return oldval;
+}
+
+/*************************************************************************/
+
+static WINAPI void *InterlockedExchangePointer(void **var, void *newval)
+{
+    void *oldval = *var;
+    *var = newval;
+    return oldval;
+}
+
+/*************************************************************************/
+
+static WINAPI int32_t InterlockedIncrement(int32_t *var)
+{
+    return ++*var;
+}
+
+/*************************************************************************/
+
+static WINAPI int32_t InterlockedTestExchange(int32_t *var, int32_t testval,
+                                              int32_t newval)
+{
+    int32_t oldval = *var;
+    if (oldval == testval)
+        *var = newval;
+    return oldval;
+}
+
+/*************************************************************************/
+
+static WINAPI int LCMapStringA
+        (uint32_t locale, uint32_t flags, const char *in, int inlen,
+         char *out, int outsize)
+{
+    if (!in || !inlen || outsize < 0 || (outsize > 0 && !out)) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    if (inlen < 0)
+        inlen = strlen(in) + 1;  // include terminating null
+    if (outsize == 0)
+        return inlen;
+    if (outsize < inlen) {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        return 0;
+    }
+    memcpy(out, in, inlen);
+    return inlen;
+}
+
+/*************************************************************************/
+
+static WINAPI int LCMapStringW
+        (uint32_t locale, uint32_t flags, const uint16_t *in, int inlen,
+         uint16_t *out, int outsize)
+{
+    if (!in || !inlen || outsize < 0 || (outsize > 0 && !out)) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    if (inlen < 0) {
+        inlen = 0;
+        while (in[inlen])
+            inlen++;
+        inlen++;  // include null terminator
+    }
+    if (outsize == 0)
+        return inlen;
+    if (outsize < inlen) {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        return 0;
+    }
+    memcpy(out, in, inlen*2);
+    return inlen;
+}
+
+/*************************************************************************/
+
+static WINAPI void LeaveCriticalSection(void *lock)
+{
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t LoadLibraryA(char *filename)
+{
+    return GetModuleHandleA(filename);
+}
+
+/*************************************************************************/
+
+static WINAPI int MultiByteToWideChar
+        (unsigned int codepage, uint32_t flags, const unsigned char *in,
+         int inlen, uint16_t *out, int outsize)
+{
+    int i, outlen;
+
+    if (!in || !inlen || outsize < 0 || (outsize > 0 && !out)) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    if (inlen < 0) {
+        inlen = 0;
+        while (in[inlen])
+            inlen++;
+        inlen++;  // include null terminator
+    }
+    outlen = 0;
+
+    for (i = 0; i < inlen; i++) {
+        if (out) {
+            if (outlen >= outsize) {
+                SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                return 0;
+            }
+            *out++ = in[i];
+        }
+        outlen++;
+    }
+
+    return outlen;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t QueryPerformanceCounter(int64_t *result)
+{
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    if (!result) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    *result = (int64_t)tv.tv_sec*1000000 + tv.tv_usec;  // sure, why not?
+    return 1;
+}
+
+/*************************************************************************/
+
+static WINAPI int ReleaseSemaphore(uint32_t sem, int32_t release_count,
+                                   int32_t *previous)
+{
+    if (sem != HANDLE_SEMAPHORE) {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return 0;
+    }
+    if (previous)
+        *previous = 0;
+    return 1;
+}
+
+/*************************************************************************/
+
+static WINAPI void SetHandleCount(uint32_t count)
+{
+    /* obsolete Win16 function, does nothing */
+}
+
+/*************************************************************************/
+
+static WINAPI void SetLastError(uint32_t error)
+{
+    w32_errno = error;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t TlsAlloc(void)
+{
+    int i;
+    for (i = 0; i < TLS_MINIMUM_AVAILABLE; i++) {
+        if (!tls_alloced[i]) {
+            tls_alloced[i] = 1;
+            D((fprintf(stderr, "TlsAlloc() succeeded with %d\n", i)));
+            return i;
+        }
+    }
+    D((fprintf(stderr, "TlsAlloc() failed\n")));
+    return ~0;
+}
+
+/*************************************************************************/
+
+static WINAPI int TlsFree(uint32_t index)
+{
+    if (index >= TLS_MINIMUM_AVAILABLE) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    tls_alloced[index] = 0;
+    return 1;
+}
+
+/*************************************************************************/
+
+static WINAPI void *TlsGetValue(uint32_t index)
+{
+    if (index >= TLS_MINIMUM_AVAILABLE) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return NULL;
+    }
+    SetLastError(NO_ERROR);
+    return tls_data[index];
+}
+
+/*************************************************************************/
+
+static WINAPI int TlsSetValue(uint32_t index, void *value)
+{
+    if (index >= TLS_MINIMUM_AVAILABLE) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    tls_data[index] = value;
+    return 1;
+}
+
+/*************************************************************************/
+
+static WINAPI uint32_t WaitForSingleObject(uint32_t handle, uint32_t msec)
+{
+    return 0;  /* or WAIT_TIMEOUT == 0x102 */
+}
+
+/*************************************************************************/
+
+static WINAPI int WideCharToMultiByte
+        (unsigned int codepage, uint32_t flags, const uint16_t *in, int inlen,
+         char *out, int outsize, const char *defchar, int *defchar_used)
+{
+    int i, outlen;
+
+    if (!in || !inlen || outsize < 0 || (outsize > 0 && !out)) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    if (inlen < 0) {
+        inlen = 0;
+        while (in[inlen])
+            inlen++;
+        inlen++;  // include null terminator
+    }
+    if (!defchar)
+        defchar = "?";
+    outlen = 0;
+
+    /* Simple implementation (FIXME look into glibc's conversion functions?) */
+    for (i = 0; i < inlen; i++) {
+        if (in[i] <= 0x7F) {
+            if (out) {
+                if (outlen >= outsize) {
+                    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                    return 0;
+                }
+                *out++ = (char)in[i];
+            }
+            outlen++;
+        } else {
+            if (out) {
+                const char *s;
+                if (outlen + strlen(defchar) > outsize) {
+                    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                    return 0;
+                }
+                s = defchar;
+                while (*s)
+                    *out++ = *s++;
+            }
+            outlen += strlen(defchar);
+            if (defchar_used)
+                *defchar_used = 1;
+        }
+    }
+
+    return outlen;
+}
+
+/*************************************************************************/
+
+static WINAPI int WriteFile(uint32_t file, const void *buf, uint32_t len,
+                            uint32_t *written, void *overlapped)
+{
+    int fd = -1, nwritten;
+
+    if (!buf) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    if (file == HANDLE_STDIN) {
+        SetLastError(ERROR_ACCESS_DENIED);
+        return 0;
+    } else if (file == HANDLE_STDOUT) {
+        D((fd = 1));
+    } else if (file == HANDLE_STDERR) {
+        D((fd = 2));
+    } else {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return 0;
+    }
+    if (len == 0) {
+        if (written)
+            *written = 0;
+        return 1;
+    }
+    if (fd < 0) {
+        /* Suppress stdout/stderr output in non-debug mode */
+        if (written)
+            *written = len;
+        return 1;
+    }
+
+    do {
+        errno = 0;
+        nwritten = write(fd, buf, len);
+    } while (nwritten <= 0 && errno == EINTR);
+    if (nwritten <= 0) {
+        if (errno == EBADF || errno == EINVAL)
+            SetLastError(ERROR_ACCESS_DENIED);
+        else if (errno == EFAULT)
+            SetLastError(ERROR_INVALID_ACCESS);
+        else if (errno == EPIPE)
+            SetLastError(ERROR_BROKEN_PIPE);
+        else if (errno == EAGAIN)
+            SetLastError(ERROR_IO_PENDING);
+        else if (errno == ENOSPC || errno == EFBIG)
+            SetLastError(ERROR_DISK_FULL);
+        else if (errno == EIO)
+            SetLastError(ERROR_WRITE_FAULT);
+        else
+            SetLastError(ERROR_UNKNOWN);
+        return 0;
+    }
+
+    if (written)
+        *written = (uint32_t)nwritten;
+    return 1;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* USER32 functions. */
+
+/*************************************************************************/
+
+static WINAPI uint32_t GetActiveWindow(void)
+{
+    return HANDLE_WINDOW;
+}
+
+/*************************************************************************/
+
+#define OUT(str) do {                           \
+    const char *__s = str;                      \
+    do {                                        \
+        int __len, __lpad, __rpad;              \
+        const char *__t = __s + strlen(__s);    \
+        if (__t - __s > maxline)                \
+            __t = __s + maxline;                \
+        __len = __t - __s;                      \
+        __lpad = (maxline - __len) / 2;         \
+        __rpad = maxline - __len - __lpad;      \
+        fprintf(stderr, "|%*s%.*s%*s|\n", __lpad, "", __len, __s, __rpad, "");\
+        __s = __t;                              \
+    } while (*__s);                             \
+} while (0)
+#define MAXLINEWIDTH 77
+
+static WINAPI int MessageBoxA(uint32_t window, const char *text,
+                              const char *title, unsigned int type)
+{
+    char *mytext, *s;
+    int maxline, i;
+    char dashbuf[MAXLINEWIDTH+1];
+
+    if (!text || !title) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    mytext = strdup(text);  // make sure we can strtok() it
+    if (!mytext) {
+        SetLastError(ERROR_OUTOFMEMORY);
+        return 0;
+    }
+
+    maxline = strlen(title);
+    for (s = mytext; *s; s += strspn(s, "\r\n")) {
+        char *t = s + strcspn(s, "\r\n");
+        if (t-s > maxline)
+            maxline = t-s;
+        s = t;
+    }
+    if (maxline > MAXLINEWIDTH)
+        maxline = MAXLINEWIDTH;
+    for (i = 0; i < maxline; i++)
+        dashbuf[i] = '-';
+    dashbuf[maxline] = 0;
+
+    fprintf(stderr, "+%s+\n", dashbuf);
+    OUT(title);
+    fprintf(stderr, "+%s+\n", dashbuf);
+    for (s = strtok(mytext,"\r\n"); s; s = strtok(NULL,"\r\n"))
+        OUT(s);
+    fprintf(stderr, "+%s+\n", dashbuf);
+
+    free(mytext);
+    return 1;
+}
+
+#undef OUT
+#undef MAXLINEWIDTH
+
+/*************************************************************************/
+
+static WINAPI int MessageBoxW(uint32_t window, const uint16_t *text,
+                              const uint16_t *title, unsigned int type)
+{
+    char textbuf[10000], titlebuf[1000];
+    if (!WideCharToMultiByte(0, 0, text, 0, textbuf, sizeof(textbuf), 0, 0))
+        strcpy(textbuf, "<<buffer overflow>>");
+    if (!WideCharToMultiByte(0, 0, title, 0, titlebuf, sizeof(titlebuf), 0, 0))
+        strcpy(titlebuf, "<<buffer overflow>>");
+    return MessageBoxA(window, textbuf, titlebuf, type);;
+}
+
+/*************************************************************************/
+/*************************************************************************/
diff -urN ffmpeg-3.2.1-orig/libavcodec/w32dll-emu.h ffmpeg-3.2.1/libavcodec/w32dll-emu.h
--- ffmpeg-3.2.1-orig/libavcodec/w32dll-emu.h	1970-01-01 09:00:00 +0900
+++ ffmpeg-3.2.1/libavcodec/w32dll-emu.h	2016-12-06 15:02:29 +0900
@@ -0,0 +1,201 @@
+/*
+ * w32dll-emu.h -- w32dll.c internal header file for Win32 emulation
+ * Written by Andrew Church <achurch@achurch.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef W32DLL_EMU_H
+#define W32DLL_EMU_H
+
+/*************************************************************************/
+
+/* Function pointer return types. (Note that on the whole, we avoid using
+ * Windows types in favor of standard ANSI types like uint32_t.) */
+typedef CALLBACK long (*FARPROC)(void);
+
+/*************************************************************************/
+
+/* Various constants. */
+
+/* Local handle constants.  HANDLE_DEFAULT (for the DLL itself) is defined
+ * in w32dll-local.h. */
+#define HANDLE_KERNEL32                 2
+#define HANDLE_USER32                   3
+#define HANDLE_WINDOW                   101
+#define HANDLE_HEAP                     201
+#define HANDLE_STDIN                    301
+#define HANDLE_STDOUT                   302
+#define HANDLE_STDERR                   303
+#define HANDLE_SEMAPHORE                401
+#define HANDLE_MAXLOCAL                 4095
+
+#define INVALID_HANDLE_VALUE            (~0)
+
+#define TLS_MINIMUM_AVAILABLE           64
+
+#define ERROR_UNKNOWN                   99999
+#define NO_ERROR                        0
+#define ERROR_INVALID_FUNCTION          1
+#define ERROR_FILE_NOT_FOUND            2
+#define ERROR_ACCESS_DENIED             5
+#define ERROR_INVALID_HANDLE            6
+#define ERROR_NOT_ENOUGH_MEMORY         8
+#define ERROR_INVALID_ACCESS            12
+#define ERROR_OUTOFMEMORY               14
+#define ERROR_WRITE_FAULT               29
+#define ERROR_INVALID_PARAMETER         87
+#define ERROR_BROKEN_PIPE               109
+#define ERROR_DISK_FULL                 112
+#define ERROR_INSUFFICIENT_BUFFER       122
+#define ERROR_IO_PENDING                997
+
+/*************************************************************************/
+
+/* Various structures. */
+
+typedef struct {
+    unsigned int maxbytes;
+    uint8_t defchar[2];
+    uint8_t leadbytes[12];
+} CPINFO;
+
+typedef struct {
+    uint32_t size;
+    uint32_t major;     // set to 5
+    uint32_t minor;     // set to 0 (5.0: Windows 2000)
+    uint32_t build;     // can be anything
+    uint32_t platform;  // set to 2 (VER_PLATFORM_WIN32_NT)
+    char extra[128];
+    uint16_t sp_major;  // set to 4 (W2k SP4)
+    uint16_t sp_minor;  // set to 0
+    uint16_t suite;     // set to 0
+    uint8_t type;       // set to 0x01 (VER_NT_WORKSTATION)
+    uint8_t reserved;
+} OSVERSIONINFOEX;
+
+typedef struct {
+    uint32_t size;
+    const char *reserved;
+    const char *desktop;
+    const char *title;
+    uint32_t x, y, w, h, wchars, hchars, fill;
+    uint32_t flags;
+    uint16_t show;
+    uint16_t reserved2;
+    uint8_t *reserved3;
+    uint32_t h_stdin;
+    uint32_t h_stdout;
+    uint32_t h_stderr;
+} STARTUPINFO;
+
+/*************************************************************************/
+
+/* Emulated function prototypes (these are all static within w32dll-emu.c). */
+
+/**** KERNEL32.dll ****/
+
+static WINAPI int      CloseHandle(uint32_t handle);
+static WINAPI uint32_t CreateSemaphoreA(void *attr, uint32_t initial,
+                                        uint32_t max, const char *name);
+static WINAPI uint32_t CreateSemaphoreW(void *attr, uint32_t initial,
+                                        uint32_t max, const uint16_t *name);
+static WINAPI void     DeleteCriticalSection(void *lock);
+static WINAPI void     EnterCriticalSection(void *lock);
+static WINAPI void     ExitProcess(unsigned int exitcode);
+static WINAPI int      FreeEnvironmentStringsA(void *env);
+static WINAPI int      FreeEnvironmentStringsW(void *env);
+static WINAPI unsigned int
+                       GetACP(void);
+static WINAPI int      GetCPInfo(unsigned int codepage, CPINFO *result);
+static WINAPI char *   GetCommandLineA(void);
+static WINAPI int      GetConsoleMode(uint32_t file, uint16_t *result);
+static WINAPI uint32_t GetCurrentProcessId(void);
+static WINAPI uint32_t GetCurrentThreadId(void);
+static WINAPI void *   GetEnvironmentStringsA(void);
+static WINAPI void *   GetEnvironmentStringsW(void);
+static WINAPI uint32_t GetFileType(uint32_t file);
+static WINAPI uint32_t GetLastError(void);
+static WINAPI uint32_t GetModuleFileNameA(uint32_t module, char *buf,
+                                          uint32_t size);
+static WINAPI uint32_t GetModuleHandleA(const char *name);
+static WINAPI FARPROC  GetProcAddress(uint32_t handle, const char *name);
+static WINAPI uint32_t GetProcessHeap(void);
+static WINAPI void     GetStartupInfoA(STARTUPINFO *result);
+static WINAPI uint32_t GetStdHandle(uint32_t index);
+static WINAPI int      GetStringTypeW(uint32_t type, const uint16_t *str,
+                                      int len, uint16_t *typebuf);
+static WINAPI void     GetSystemTimeAsFileTime(uint64_t *result);
+static WINAPI uint32_t GetTickCount(void);
+static WINAPI int      GetVersionExA(OSVERSIONINFOEX *result);
+static WINAPI void *   HeapAlloc(uint32_t heap, uint32_t flags, size_t size);
+static WINAPI uint32_t HeapCreate(uint32_t flags, size_t initial, size_t max);
+static WINAPI int      HeapDestroy(uint32_t heap);
+static WINAPI int      HeapFree(uint32_t heap, uint32_t flags, void *ptr);
+static WINAPI void *   HeapReAlloc(uint32_t heap, uint32_t flags, void *ptr,
+                                   size_t size);
+static WINAPI uint32_t HeapSize(uint32_t heap, uint32_t flags, const void*ptr);
+static WINAPI int32_t  InterlockedCompareExchange
+                            (int32_t *var, int32_t testval, int32_t newval);
+static WINAPI void *   InterlockedCompareExchangePointer
+                                 (void ***var, void *testval, void *newval);
+static WINAPI int32_t  InterlockedDecrement(int32_t *var);
+static WINAPI int32_t  InterlockedExchange(int32_t *var, int32_t newval);
+static WINAPI int32_t  InterlockedExchangeAdd(int32_t *var, int32_t addval);
+static WINAPI void *   InterlockedExchangePointer(void **var, void *newval);
+static WINAPI int32_t  InterlockedIncrement(int32_t *var);
+static WINAPI int32_t  InterlockedTestExchange(int32_t *var, int32_t testval,
+                                               int32_t newval);
+static WINAPI void     InitializeCriticalSection(void *lock);
+static WINAPI int LCMapStringA
+        (uint32_t locale, uint32_t flags, const char *in, int inlen,
+         char *out, int outsize);
+static WINAPI int LCMapStringW
+        (uint32_t locale, uint32_t flags, const uint16_t *in, int inlen,
+         uint16_t *out, int outsize);
+static WINAPI void     LeaveCriticalSection(void *lock);
+static WINAPI uint32_t LoadLibraryA(char *filename);
+static WINAPI int      MultiByteToWideChar
+        (unsigned int codepage, uint32_t flags, const unsigned char *in,
+         int inlen, uint16_t *out, int outsize);
+static WINAPI uint32_t QueryPerformanceCounter(int64_t *result);
+static WINAPI int      ReleaseSemaphore(uint32_t sem, int32_t release_count,
+                                        int32_t *previous);
+static WINAPI void     SetHandleCount(uint32_t count);
+static WINAPI void     SetLastError(uint32_t error);
+static WINAPI uint32_t TlsAlloc(void);
+static WINAPI int      TlsFree(uint32_t index);
+static WINAPI void *   TlsGetValue(uint32_t index);
+static WINAPI int      TlsSetValue(uint32_t index, void *value);
+static WINAPI uint32_t WaitForSingleObject(uint32_t handle, uint32_t msec);
+static WINAPI int      WideCharToMultiByte
+        (unsigned int codepage, uint32_t flags, const uint16_t *in, int inlen,
+         char *out, int outsize, const char *defchar, int *defchar_used);
+static WINAPI int      WriteFile(uint32_t file, const void *buf, uint32_t len,
+                                 uint32_t *written, void *overlapped);
+
+/**** USER32.dll ****/
+
+static WINAPI uint32_t GetActiveWindow(void);
+static WINAPI int      MessageBoxA(uint32_t window, const char *text,
+                                   const char *title, unsigned int type);
+static WINAPI int      MessageBoxW(uint32_t window, const uint16_t *text,
+                                   const uint16_t *title, unsigned int type);
+
+/*************************************************************************/
+
+#endif /* W32DLL_EMU_H */
diff -urN ffmpeg-3.2.1-orig/libavcodec/w32dll-local.h ffmpeg-3.2.1/libavcodec/w32dll-local.h
--- ffmpeg-3.2.1-orig/libavcodec/w32dll-local.h	1970-01-01 09:00:00 +0900
+++ ffmpeg-3.2.1/libavcodec/w32dll-local.h	2016-12-06 15:02:29 +0900
@@ -0,0 +1,216 @@
+/*
+ * w32dll-local.h -- w32dll.c internal header file
+ * Written by Andrew Church <achurch@achurch.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef W32DLL_LOCAL_H
+#define W32DLL_LOCAL_H
+
+/*************************************************************************/
+
+/* Win-PE executable file structures. */
+
+/************************************/
+
+/* DOS executable header */
+
+struct dos_header {
+    uint16_t signature;         /* DOS_EXE_SIGNATURE */
+    uint16_t len_bytes;         /* 1..512 */
+    uint16_t len_sectors;
+    uint16_t reloc_count;
+    uint16_t len_header;
+    uint16_t min_extra_mem;
+    uint16_t max_extra_mem;
+    uint16_t init_ss;
+    uint16_t init_sp;
+    uint16_t checksum;
+    uint16_t init_cs;
+    uint16_t init_ip;
+    uint16_t reloc_offset;
+    uint16_t overlay_num;
+    uint8_t ignore1C[0x20];     /* 0x1C..0x3B */
+    uint16_t winheader;
+    uint16_t ignore3E;
+};
+
+#define DOS_EXE_SIGNATURE 0x5A4D  /* 'MZ' */
+
+/************************************/
+
+/* Win-PE executable headers (base and optional) */
+
+enum rva_index {
+    RVA_EXPORT = 0,
+    RVA_IMPORT,
+    RVA_RESOURCE,
+    RVA_EXCEPTION,
+    RVA_CERTIFICATE,
+    RVA_BASE_RELOC,
+    RVA_DEBUG,
+    RVA_ARCH,
+    RVA_GLOBAL_PTR,
+    RVA_TLS_TABLE,
+    RVA_LOAD_CONFIG,
+    RVA_BOUND_IMPORT,
+    RVA_IMPORT_ADDR,
+    RVA_DELAY_IMPORT,
+    RVA_MAX
+};
+
+struct pe_header {
+    uint32_t signature;         /* WIN_PE_SIGNATURE */
+    uint16_t arch;              /* WIN_PE_ARCH_xxx */
+    uint16_t nsections;
+    uint32_t timestamp;
+    uint32_t sym_table_offset;
+    uint32_t nsyms;
+    uint16_t opt_header_size;
+    uint16_t flags;             /* WIN_PE_FLAG_xxx */
+};
+struct pe_ext_header {
+    uint16_t magic;             /* WIN_PE_OPT_MAGIC_xxx */
+    uint8_t linkver_major;
+    uint8_t linkver_minor;
+    uint32_t code_size;
+    uint32_t data_size;
+    uint32_t bss_size;
+    uint32_t entry_point;
+    uint32_t code_base;
+    uint32_t data_base;
+    uint32_t image_base;        /* Code assumes it's loaded at this address */
+    uint32_t section_align;
+    uint32_t file_align;
+    uint16_t osver_major;
+    uint16_t osver_minor;
+    uint16_t imagever_major;
+    uint16_t imagever_minor;
+    uint16_t subsysver_major;
+    uint16_t subsysver_minor;
+    uint32_t win32_ver;
+    uint32_t image_size;
+    uint32_t header_size;
+    uint32_t checksum;
+    uint16_t subsystem;
+    uint16_t dll_flags;         /* Ignored here */
+    uint32_t stack_reserve;
+    uint32_t stack_commit;
+    uint32_t heap_reserve;
+    uint32_t heap_commit;
+    uint32_t loader_flags;
+    uint32_t nrva;
+    struct {
+        uint32_t address;
+        uint32_t size;
+    } rva[RVA_MAX];
+};
+
+#define WIN_PE_SIGNATURE    0x00004550  /* 'PE\0\0' */
+
+#define WIN_PE_ARCH_X86         0x014C  /* Ignore the lower 2 bits for this */
+#define WIN_PE_ARCH_IA64        0x0200
+#define WIN_PE_ARCH_X86_64      0x8664
+
+#define WIN_PE_FLAG_DLL         0x2000
+
+#define WIN_PE_OPT_MAGIC_32     0x010B  /* 32-bit code */
+#define WIN_PE_OPT_MAGIC_64     0x020B  /* 64-bit code */
+
+/************************************/
+
+/* Section table */
+
+struct pe_section_header {
+    char name[8];
+    uint32_t virtsize;
+    uint32_t virtaddr;
+    uint32_t filesize;
+    uint32_t fileaddr;
+    uint32_t reloc_table;
+    uint32_t linenum_table;
+    uint16_t nrelocs;
+    uint16_t nlinenums;
+    uint32_t flags;             /* SECTION_FLAG_xxx */
+};
+
+#define SECTION_FLAG_CODE   0x00000020
+#define SECTION_FLAG_DATA   0x00000040
+#define SECTION_FLAG_BSS    0x00000080
+#define SECTION_FLAG_EXEC   0x20000000
+#define SECTION_FLAG_READ   0x40000000
+#define SECTION_FLAG_WRITE  0x80000000
+
+/************************************/
+
+/* Export directory */
+
+struct export_directory {
+    uint32_t flags;
+    uint32_t timestamp;
+    uint16_t version_major;
+    uint16_t version_minor;
+    uint32_t name;              /* Address of name in section */
+    uint32_t ordinal_base;
+    uint32_t nfuncs;
+    uint32_t nnames;
+    uint32_t func_table;
+    uint32_t name_table;
+    uint32_t name_ordinal_table;
+};
+
+/************************************/
+
+/* Import directory */
+
+struct import_directory {
+    uint32_t import_table;
+    uint32_t timestamp;
+    uint32_t forward;
+    uint32_t module_name;
+    uint32_t import_addr_table;
+};
+
+struct import_name_entry {
+    uint16_t hint;
+    char name[1];       /* As long as necessary, null-terminated */
+};
+
+/*************************************************************************/
+
+/* Constants for the DllMain() function (entry point). */
+#define DLL_PROCESS_DETACH      0
+#define DLL_PROCESS_ATTACH      1
+#define DLL_THREAD_ATTACH       2
+#define DLL_THREAD_DETACH       3
+
+/* Handle value for "this module" (FIXME: assumes only one module). */
+#define HANDLE_DEFAULT          1
+
+/*************************************************************************/
+
+/* Internal function prototypes. */
+
+extern void *w32dll_emu_import_by_name(const char *module,
+                                       const struct import_name_entry *name);
+extern void *w32dll_emu_import_by_ordinal(const char *module,
+                                          uint32_t ordinal);
+
+/*************************************************************************/
+
+#endif  /* W32DLL_LOCAL_H */
diff -urN ffmpeg-3.2.1-orig/libavcodec/w32dll.c ffmpeg-3.2.1/libavcodec/w32dll.c
--- ffmpeg-3.2.1-orig/libavcodec/w32dll.c	1970-01-01 09:00:00 +0900
+++ ffmpeg-3.2.1/libavcodec/w32dll.c	2016-12-06 15:03:18 +0900
@@ -0,0 +1,1193 @@
+/*
+ * w32dll.c -- a simplistic interface to Win32 DLLs (no thread support)
+ * Written by Andrew Church <achurch@achurch.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/mman.h>
+
+#include "w32dll.h"
+#include "w32dll-local.h"
+
+#if !defined(__linux__)
+# error Sorry, only implemented on Linux.
+#endif
+#if !ARCH_X86
+# error Sorry, this requires an x86 architecture.
+#endif
+
+#define GETPAGESIZE() (sysconf(_SC_PAGESIZE))
+#define MAP_ANONYMOUS 0x20
+#define MAP_32BIT 0x40
+
+/*************************************************************************/
+
+/* Contents of a DLL handle. */
+
+struct w32dllhandle_ {
+    /* Signature (to protect against bad pointers and double-free) */
+    uint32_t signature;
+
+    /* Overall file data */
+    struct pe_header header;
+    struct pe_ext_header extheader;
+
+    /* File position for each RVA entry */
+    off_t rva_filepos[RVA_MAX];
+
+    /* Data for each loaded section */
+    int nsections;
+    struct section_info {
+        void *base;
+        uint32_t size;
+        int prot;               /* Protection flags for mprotect() */
+        uint32_t origbase;      /* Virtual address given in section header */
+        uint32_t origsize;      /* Likewise, for size */
+    } *sections;
+
+    /* Data for exported functions */
+    int export_ordinal_base;
+    int export_ordinal_count;
+    void **export_table;
+    int export_name_count;
+    struct export_name {
+        char *name;
+        uint32_t ordinal;
+    } *export_name_table;
+};
+
+#define HANDLE_SIGNATURE    0xD11DA7A5
+
+
+/* Forward declarations for internal routines. */
+
+static int w32dll_add_section(W32DLLHandle dll, int fd,
+                              struct pe_section_header *secthdr);
+static int w32dll_load_section(int fd, struct pe_section_header *secthdr,
+                               struct section_info *sectinfo);
+static void w32dll_update_rva(W32DLLHandle dll,
+                              struct pe_section_header *secthdr);
+static int w32dll_read_exports(W32DLLHandle dll, int fd);
+static int w32dll_process_imports(W32DLLHandle dll,
+                                  struct import_directory *importdir);
+static void *w32dll_import_by_name(const char *module,
+                                   const struct import_name_entry *name);
+static void *w32dll_import_by_ordinal(const char *module, uint32_t ordinal);
+static int w32dll_read_relocs(W32DLLHandle dll, int fd,
+                              uint32_t **relocs_ptr, int *nrelocs_ptr);
+static void w32dll_relocate(W32DLLHandle dll, uint32_t *relocs, int nrelocs);
+static void *w32dll_relocate_addr(W32DLLHandle dll, uint32_t addr);
+static char *w32dll_read_asciiz(int fd);
+static int w32dll_init_fs(void);
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* External interface routines. */
+
+/*************************************************************************/
+
+/**
+ * w32dll_load:  Load the given DLL file into memory, and return a handle
+ * to it.
+ *
+ * Parameters:
+ *       path: DLL file pathname.
+ *     compat: If nonzero, adds a memory mapping for the entire DLL to
+ *             accommodate misbehaving DLLs that access memory outside the
+ *             registered sections.
+ * Return value:
+ *     DLL handle (nonzero), or zero on error.
+ * Side effects:
+ *     Sets errno to an appropriate value on error, including ENOEXEC if
+ *     the file is not recognized as a Win32 DLL file or is corrupt or
+ *     truncated, or ETXTBSY if the DLL's DllMain() function returns an
+ *     error.  On successful return, errno is undefined.
+ */
+
+W32DLLHandle w32dll_load(const char *path, int compat)
+{
+    W32DLLHandle dll;
+    struct dos_header doshdr;
+    int fd, i;
+
+    /* Allocate and initialize the DLL handle. */
+    dll = malloc(sizeof(*dll));
+    if (!dll)
+        return NULL;
+    memset(&dll->header, 0, sizeof(dll->header));
+    memset(&dll->extheader, 0, sizeof(dll->extheader));
+    memset(&dll->rva_filepos, 0, sizeof(dll->rva_filepos));
+    dll->signature            = HANDLE_SIGNATURE;
+    dll->nsections            = 0;
+    dll->sections             = NULL;
+    dll->export_ordinal_base  = 0;
+    dll->export_ordinal_count = 0;
+    dll->export_table         = NULL;
+    dll->export_name_count    = 0;
+    dll->export_name_table    = NULL;
+
+    /* Open the file, and ensure that it's seekable. */
+    fd = open(path, O_RDONLY);
+    if (fd == -1 || lseek(fd, 0, SEEK_SET) == -1) {
+        int errno_save = errno;
+        free(dll);
+        errno = errno_save;
+        return NULL;
+    }
+
+    /* Check for a valid (Win32-style) DOS executable header. */
+    if (read(fd, &doshdr, sizeof(doshdr)) != sizeof(doshdr)
+     || doshdr.signature != DOS_EXE_SIGNATURE
+     || doshdr.reloc_offset < 0x40
+    ) {
+        goto err_noexec;
+    }
+
+    /* Check for a valid PE header (standard and optional both required). */
+    if (lseek(fd, doshdr.winheader, SEEK_SET) == -1
+     || read(fd, &dll->header, sizeof(dll->header)) != sizeof(dll->header)
+     || dll->header.opt_header_size < sizeof(dll->extheader)
+     || read(fd, &dll->extheader, sizeof(dll->extheader))
+                                                  != sizeof(dll->extheader)
+     || dll->header.signature != WIN_PE_SIGNATURE
+     || !(dll->header.flags & WIN_PE_FLAG_DLL)
+     || (dll->header.arch & ~3) != WIN_PE_ARCH_X86
+     || dll->extheader.magic != WIN_PE_OPT_MAGIC_32
+    ) {
+        goto err_noexec;
+    }
+    /* Skip past any extra header bytes we didn't need. */
+    if (dll->header.opt_header_size > sizeof(dll->extheader)) {
+        if (lseek(fd, dll->header.opt_header_size - sizeof(dll->extheader),
+                  SEEK_CUR) == -1
+        ) {
+            goto err_noexec;
+        }
+    }
+
+    /* Go through the section table and attempt to load each section.  Also
+     * determine file positions for each RVA entry.  Note that we do not
+     * simply map the entire file because (1) sections may be larger in
+     * memory than in the file and (2) the system's page size may be larger
+     * than that specified in the file. */
+    for (i = 0; i < dll->header.nsections + (compat ? 1 : 0); i++) {
+        struct pe_section_header secthdr;
+
+        if (i >= dll->header.nsections) {
+            /* Set up compatibility entry */
+            off_t curpos = lseek(fd, 0, SEEK_CUR);
+            off_t filesize = lseek(fd, 0, SEEK_END);
+            if (curpos==-1 || filesize==-1 || lseek(fd,curpos,SEEK_SET)==-1)
+                goto error;
+            secthdr.virtaddr = 0;
+            secthdr.virtsize = dll->extheader.image_size;
+            secthdr.fileaddr = 0;
+            secthdr.filesize = filesize;
+            secthdr.flags = SECTION_FLAG_DATA | SECTION_FLAG_READ;
+        } else {
+            if (read(fd, &secthdr, sizeof(secthdr)) != sizeof(secthdr)) 
+                goto err_noexec;
+        }
+        w32dll_update_rva(dll, &secthdr);
+        w32dll_add_section(dll, fd, &secthdr);
+    }
+
+    /* Load and process relocations.  Note that once the sections are
+     * loaded, we could theoretically just retrieve these (and the other
+     * data below) from memory, but since we take the approach of only
+     * loading/mapping the sections we need, we do this the hard way and
+     * read the data directly from the file. */
+    if (dll->rva_filepos[RVA_BASE_RELOC]
+     && dll->extheader.rva[RVA_BASE_RELOC].size
+    ) {
+        uint32_t *relocs = NULL;
+        int nrelocs = 0;
+
+        if (lseek(fd, dll->rva_filepos[RVA_BASE_RELOC], SEEK_SET) == -1)
+            goto error;
+        while (lseek(fd, 0, SEEK_CUR)
+               <= dll->rva_filepos[RVA_BASE_RELOC]
+                  + dll->extheader.rva[RVA_BASE_RELOC].size - 8
+        ) {
+            int res = w32dll_read_relocs(dll, fd, &relocs, &nrelocs);
+            if (res < 0)
+                goto error;
+            if (res == 0)
+                break;
+        }
+        w32dll_relocate(dll, relocs, nrelocs);
+    }
+
+    /* Load export table. */
+    if (dll->rva_filepos[RVA_EXPORT]
+     && dll->extheader.rva[RVA_EXPORT].size >= sizeof(struct export_directory)
+    ) {
+        if (!w32dll_read_exports(dll, fd))
+            goto error;
+    }
+
+    /* Load and process import table. */
+    if (dll->rva_filepos[RVA_IMPORT]
+     && dll->extheader.rva[RVA_IMPORT].size >= sizeof(struct import_directory)
+    ) {
+        struct import_directory importdir;
+
+        if (lseek(fd, dll->rva_filepos[RVA_IMPORT], SEEK_SET) == -1)
+            goto error;
+        while (lseek(fd, 0, SEEK_CUR)
+               <= dll->rva_filepos[RVA_IMPORT]
+                  + dll->extheader.rva[RVA_IMPORT].size - sizeof(importdir)
+        ) {
+            if (read(fd, &importdir, sizeof(importdir)) != sizeof(importdir))
+                goto err_noexec;
+            if (!importdir.module_name)
+                break;  /* Last entry in table */
+            if (!importdir.import_table || !importdir.import_addr_table)
+                goto err_noexec;
+            if (!w32dll_process_imports(dll, &importdir))
+                goto error;
+        }
+    }
+
+    /* Set section access privileges appropriately. */
+    for (i = 0; i < dll->nsections; i++) {
+        if (mprotect(dll->sections[i].base, dll->sections[i].size,
+                     dll->sections[i].prot) != 0
+        ) {
+            goto error;
+        }
+    }
+
+    /* Close file descriptor (no longer needed). */
+    close(fd);
+    fd = -1;
+
+    /* Set up the FS register with a dummy thread information block.
+     * We explicitly don't support libraries that depend on the OS to
+     * put things here; we just provide the space so that accesses to
+     * %fs:... don't segfault. */
+    if (!w32dll_init_fs())
+        goto error;
+
+    /* Call the DllMain() entry point. */
+    if (dll->extheader.entry_point) {
+        WINAPI int (*DllMain)(uint32_t handle, uint32_t reason, void *resv);
+        DllMain = w32dll_relocate_addr(dll, dll->extheader.entry_point
+                                            + dll->extheader.image_base);
+        if (!DllMain)
+            goto err_noexec;
+        if (!(*DllMain)(HANDLE_DEFAULT, DLL_PROCESS_ATTACH, NULL)) {
+            (*DllMain)(HANDLE_DEFAULT, DLL_PROCESS_DETACH, NULL);
+            errno = ETXTBSY;
+            goto error;
+        }
+    }
+
+    /* Successful! */
+    return dll;
+
+    /* Error handling */
+  err_noexec:
+    errno = ENOEXEC;
+  error:
+    w32dll_unload(dll);
+    return NULL;
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_unload:  Unload the given DLL from memory.  Does nothing if the
+ * given handle is zero or invalid.
+ *
+ * Parameters:
+ *     dll: DLL handle.
+ * Return value:
+ *     None.
+ */
+
+void w32dll_unload(W32DLLHandle dll)
+{
+    int i;
+
+    if (!dll || dll->signature != HANDLE_SIGNATURE)
+        return;
+
+    /* Call the DllMain() entry point with DLL_PROCESS_DETACH. */
+    if (dll->extheader.entry_point) {
+        WINAPI int (*DllMain)(uint32_t handle, uint32_t reason, void *resv);
+        DllMain = w32dll_relocate_addr(dll, dll->extheader.entry_point
+                                            + dll->extheader.image_base);
+        if (DllMain)
+            (*DllMain)(HANDLE_DEFAULT, DLL_PROCESS_DETACH, NULL);
+    }
+
+    /* Free DLL memory. */
+    for (i = 0; i < dll->nsections; i++) {
+        munmap(dll->sections[i].base, dll->sections[i].size);
+        dll->sections[i].base = NULL;
+        dll->sections[i].size = 0;
+    }
+    free(dll->sections);
+    dll->sections = NULL;
+    dll->nsections = 0;
+
+    /* Free export tables. */
+    free(dll->export_table);
+    dll->export_table = NULL;
+    for (i = 0; i < dll->export_name_count; i++) {
+        free(dll->export_name_table[i].name);
+        dll->export_name_table[i].name = NULL;
+    }
+    free(dll->export_name_table);
+    dll->export_name_table = NULL;
+
+    /* Free the handle structure itself. */
+    dll->signature = ~HANDLE_SIGNATURE;
+    free(dll);
+
+    return;
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_lookup_by_name:  Look up the address of an exported function in
+ * the given DLL, using the function's name.
+ *
+ * Parameters:
+ *      dll: DLL handle.
+ *     name: Function name.
+ * Return value:
+ *     Function address, or NULL on error.
+ * Side effects:
+ *     Sets errno to one of the following values on error:
+ *         EINVAL: `dll' or `name' was invalid.
+ *         ENOENT: The requested function does not exist.
+ *     On successful return, errno is undefined.
+ */
+
+void *w32dll_lookup_by_name(W32DLLHandle dll, const char *name)
+{
+    int i;
+
+    if (!dll || dll->signature != HANDLE_SIGNATURE || !name || !*name) {
+        errno = EINVAL;
+        return NULL;
+    }
+    for (i = 0; i < dll->export_name_count; i++) {
+        if (strcmp(name, dll->export_name_table[i].name) == 0) {
+            return w32dll_lookup_by_ordinal(dll,
+                                            dll->export_name_table[i].ordinal);
+        }
+    }
+    errno = ENOENT;
+    return NULL;
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_lookup_by_ordinal:  Look up the address of an exported function
+ * in the given DLL, using the function's ordinal value.
+ *
+ * Parameters:
+ *         dll: DLL handle.
+ *     ordinal: Function ordinal.
+ * Return value:
+ *     Function address, or NULL on error.
+ * Side effects:
+ *     Sets errno to one of the following values on error:
+ *         EINVAL: `dll' was invalid.
+ *         ENOENT: The requested function does not exist.
+ *     On successful return, errno is undefined.
+ */
+
+void *w32dll_lookup_by_ordinal(W32DLLHandle dll, uint32_t ordinal)
+{
+    if (!dll || dll->signature != HANDLE_SIGNATURE) {
+        errno = EINVAL;
+        return NULL;
+    }
+    if (ordinal < dll->export_ordinal_base) {
+        errno = ENOENT;
+        return NULL;
+    }
+    ordinal -= dll->export_ordinal_base;
+    if (ordinal >= dll->export_ordinal_count || !dll->export_table[ordinal]) {
+        errno = ENOENT;
+        return NULL;
+    }
+    return dll->export_table[ordinal];
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Internal routines. */
+
+/*************************************************************************/
+
+/**
+ * w32dll_add_section:  Checks the given section description, and loads it
+ * in from the DLL file, appending information to the dll->sections[]
+ * array, if appropriate.
+ *
+ * Parameters:
+ *         dll: DLL handle.
+ *          fd: File descriptor to read from.
+ *     secthdr: Pointer to section header.
+ * Return value:
+ *     Nonzero on success (including when the section was intentionally
+ *     not loaded), zero on error.
+ * Notes:
+ *     - On success, the file's current offset is not changed.
+ *     - The allocated memory will be marked read/write; after relocation,
+ *           use mprotect() to set the protection to sectinfo->prot.
+ *     - On error, errno is set appropriately.
+ */
+
+static int w32dll_add_section(W32DLLHandle dll, int fd,
+                              struct pe_section_header *secthdr)
+{
+    void *new_sections;
+
+    if (!(secthdr->flags & (SECTION_FLAG_CODE
+                          | SECTION_FLAG_DATA
+                          | SECTION_FLAG_BSS))
+    ) {
+        /* Don't know what kind of section this is, but we don't need it */
+        return 1;
+    }
+
+    if (!(secthdr->flags & (SECTION_FLAG_READ
+                          | SECTION_FLAG_WRITE
+                          | SECTION_FLAG_EXEC))
+    ) {
+        /* Don't bother loading--it wouldn't be accessible anyway */
+        return 1;
+    }
+
+    new_sections = realloc(dll->sections,
+                           sizeof(*dll->sections) * (dll->nsections+1));
+    if (!new_sections)
+        return 0;
+    dll->sections = new_sections;
+    dll->sections[dll->nsections].base = NULL;
+    dll->sections[dll->nsections].size = 0;
+    dll->sections[dll->nsections].prot = 0;
+    dll->sections[dll->nsections].origbase = 0;
+    dll->sections[dll->nsections].origsize = 0;
+    dll->nsections++;
+    if (!w32dll_load_section(fd, secthdr, &dll->sections[dll->nsections-1]))
+        return 0;
+    dll->sections[dll->nsections-1].origbase += dll->extheader.image_base;
+
+    return 1;
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_load_section:  Loads the section described by `secthdr' from the
+ * file descriptor `fd', setting the `sectinfo' structure appropriately.
+ *
+ * Parameters:
+ *           fd: File to load data from.
+ *      secthdr: Section header loaded from the file.
+ *     sectinfo: Structure to store information about the segment in.
+ * Return value:
+ *     Nonzero on success, zero on error.
+ * Notes:
+ *     - On success, the file's current offset is not changed.
+ *     - The allocated memory will be marked read/write; after relocation,
+ *           use mprotect() to set the protection to sectinfo->prot.
+ *     - On error, errno is set appropriately.
+ */
+
+static int w32dll_load_section(int fd, struct pe_section_header *secthdr,
+                               struct section_info *sectinfo)
+{
+    void *base;
+    uint32_t size, toread;
+    off_t oldofs;
+
+    uint32_t pagesize = GETPAGESIZE();
+    if ((int32_t)pagesize < 0) {
+        errno = EINVAL;
+        return 0;
+    }
+
+    size = (secthdr->virtsize + pagesize-1) / pagesize * pagesize;
+    base = mmap(NULL, size, PROT_READ | PROT_WRITE,
+                MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
+    if (base == MAP_FAILED)
+        return 0;
+
+    oldofs = lseek(fd, 0, SEEK_CUR);
+    if (oldofs == -1) {
+        munmap(base, size);
+        return 0;
+    }
+    if (secthdr->filesize < secthdr->virtsize)
+        toread = secthdr->filesize;
+    else
+        toread = secthdr->virtsize;
+    if (lseek(fd, secthdr->fileaddr, SEEK_SET) == -1
+     || read(fd, base, toread) != toread
+     || lseek(fd, oldofs, SEEK_SET) == -1
+    ) {
+        munmap(base, size);
+        errno = ENOEXEC;
+        return 0;
+    }
+
+    sectinfo->base = base;
+    sectinfo->size = size;
+    sectinfo->prot = 0;
+    if (secthdr->flags & SECTION_FLAG_READ)
+        sectinfo->prot |= PROT_READ;
+    if (secthdr->flags & SECTION_FLAG_WRITE)
+        sectinfo->prot |= PROT_WRITE;
+    if (secthdr->flags & SECTION_FLAG_EXEC)
+        sectinfo->prot |= PROT_EXEC;
+    sectinfo->origbase = secthdr->virtaddr;
+    sectinfo->origsize = secthdr->virtsize;
+
+    return 1;
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_update_rva:  Update the rva_filepos[] table in the DLL handle
+ * for any RVAs within the given segment.
+ *
+ * Parameters:
+ *         dll: DLL handle.
+ *     secthdr: Pointer to section header.
+ * Return value:
+ *     None.
+ */
+
+static void w32dll_update_rva(W32DLLHandle dll,
+                              struct pe_section_header *secthdr)
+{
+    int i;
+
+    for (i = 0; i < RVA_MAX; i++) {
+        if (!dll->rva_filepos[i]
+         && dll->extheader.rva[i].address >= secthdr->virtaddr
+         && dll->extheader.rva[i].address < secthdr->virtaddr+secthdr->virtsize
+        ) {
+            dll->rva_filepos[i] =
+                dll->extheader.rva[i].address - secthdr->virtaddr
+                                              + secthdr->fileaddr;
+        }
+    }
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_read_exports:  Read in the DLL's export table, and fill in the
+ * export data in the DLL handle.
+ *
+ * Parameters:
+ *     dll: DLL handle.
+ *      fd: File descriptor to read from.
+ * Return value:
+ *     Nonzero on success, zero on failure.
+ * Notes:
+ *     On error, errno is set appropriately.
+ */
+
+static int w32dll_read_exports(W32DLLHandle dll, int fd)
+{
+    struct export_directory exportdir;
+    off_t secofs = (off_t)dll->rva_filepos[RVA_EXPORT]
+                   - (off_t)dll->extheader.rva[RVA_EXPORT].address;
+
+    /* Read in the export table. */
+    if (lseek(fd, dll->rva_filepos[RVA_EXPORT], SEEK_SET) == -1)
+        goto error;
+    if (read(fd, &exportdir, sizeof(exportdir)) != sizeof(exportdir))
+        goto err_noexec;
+    dll->export_ordinal_base = exportdir.ordinal_base;
+
+    /* Read in each exported function address, relocate it, and store the
+     * relocated address in the DLL handle structure. */
+    if (exportdir.nfuncs) {
+        dll->export_table =
+            malloc(sizeof(*dll->export_table) * exportdir.nfuncs);
+        if (!dll->export_table)
+            goto error;
+        if (lseek(fd, exportdir.func_table + secofs, SEEK_SET) == -1)
+            goto error;
+        /* Use the entry count field itself as a loop variable, to ensure
+         * that the correct number of entries are cleaned up on error
+         * (doesn't matter here, but avoids a memory leak for the name
+         * array handling below) */
+        for (dll->export_ordinal_count = 0;
+             dll->export_ordinal_count < exportdir.nfuncs;
+             dll->export_ordinal_count++
+        ) {
+            uint32_t address;
+            if (read(fd, &address, 4) != 4)
+                goto err_noexec;
+            address += dll->extheader.image_base;
+            dll->export_table[dll->export_ordinal_count] =
+                w32dll_relocate_addr(dll, address);
+        }
+    }
+
+    /* Read in each exported function name, and store the name and its
+     * associated ordinal in the DLL handle structure. */
+    if (exportdir.nnames) {
+        int i;
+        dll->export_name_table =
+            malloc(sizeof(*dll->export_name_table) * exportdir.nnames);
+        if (!dll->export_name_table)
+            goto error;
+        if (lseek(fd, exportdir.name_ordinal_table + secofs, SEEK_SET) == -1)
+            goto error;
+        for (i = 0; i < exportdir.nnames; i++) {
+            uint16_t ordinal;
+            if (read(fd, &ordinal, 2) != 2)
+                goto err_noexec;
+            dll->export_name_table[i].ordinal =
+                dll->export_ordinal_base + ordinal;
+        }
+        for (dll->export_name_count = 0;
+             dll->export_name_count < exportdir.nnames;
+             dll->export_name_count++
+        ) {
+            uint32_t name_address;
+            char *s;
+            if (lseek(fd, exportdir.name_table+secofs+dll->export_name_count*4,
+                      SEEK_SET) == -1
+            ) {
+                goto error;
+            }
+            if (read(fd, &name_address, 4) != 4)
+                goto err_noexec;
+            if (lseek(fd, name_address + secofs, SEEK_SET) == -1)
+                goto error;
+            s = w32dll_read_asciiz(fd);
+            if (!s)
+                goto error;
+            dll->export_name_table[dll->export_name_count].name = s;
+        }
+    }
+
+    /* Success! */
+    return 1;
+
+  err_noexec:
+    errno = ENOEXEC;
+  error:
+    return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_process_imports:  Reads the list of imports described by
+ * `importdir' and sets the pointers to appropriate values (emulation
+ * functions or a placeholder function).
+ *
+ * Parameters:
+ *           dll: DLL handle.
+ *     importdir: Import directory structure.
+ * Return value:
+ *     Nonzero on success, zero on error.
+ * Notes:
+ *     - On error, errno is set appropriately.
+ *     - This routine assumes that all import data is located in the same
+ *       section.  Since the import address table has to be in a loaded
+ *       section (usually a data section), this implies that the rest of
+ *       the import data is also in a loaded section; therefore, we take
+ *       the easy approach and access the data directly in memory.
+ */
+
+static int w32dll_process_imports(W32DLLHandle dll,
+                                  struct import_directory *importdir)
+{
+    const uint32_t imgbase = dll->extheader.image_base;  // shorthand
+    const char *module;
+    const struct import_name_entry **names;
+    void **addrs;
+    int i;
+
+    /* Relocate import directory addresses. */
+    module = w32dll_relocate_addr(dll, importdir->module_name + imgbase);
+    names = w32dll_relocate_addr(dll, importdir->import_table + imgbase);
+    addrs = w32dll_relocate_addr(dll, importdir->import_addr_table + imgbase);
+    if (!module || !*module || !names || !addrs)
+        goto err_noexec;
+
+    /* Process the imports. */
+    for (i = 0; names[i]; i++) {
+        const struct import_name_entry *name;
+        uint32_t ordinal;
+        if ((uint32_t)names[i] & 0x80000000UL) {
+            name = NULL;
+            ordinal = (uint32_t)names[i] & 0x7FFFFFFFUL;
+        } else {
+            name = w32dll_relocate_addr(dll, (uint32_t)names[i] + imgbase);
+            if (!name)
+                goto err_noexec;
+        }
+        if (name)
+            addrs[i] = w32dll_import_by_name(module, name);
+        else
+            addrs[i] = w32dll_import_by_ordinal(module, ordinal);
+    }
+
+    /* All done. */
+    return 1;
+
+  err_noexec:
+    errno = ENOEXEC;
+    return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_import_by_name, w32dll_import_by_ordinal:  Return the address
+ * corresponding to the given import, selected by either name or ordinal.
+ *
+ * Parameters:
+ *      module: Name of the module from which to import.
+ *        name: Import name descriptor (w32dll_import_by_name() only).
+ *     ordinal: Import ordinal (w32dll_import_by_ordinal() only).
+ * Return value:
+ *     The address corresponding to the import, or NULL if the import
+ *     failed.
+ * Notes:
+ *     - A NULL return is *not* considered an error, and thus errno is
+ *       undefined after returning from these functions.
+ *     - Currently, these functions just ask the Win32 emulation layer for
+ *       an appropriate function, and do not handle linking between
+ *       multiple loaded DLLs.
+ */
+
+static void *w32dll_import_by_name(const char *module,
+                                   const struct import_name_entry *name)
+{
+    return w32dll_emu_import_by_name(module, name);
+}
+
+/************************************/
+
+static void *w32dll_import_by_ordinal(const char *module, uint32_t ordinal)
+{
+    return w32dll_emu_import_by_ordinal(module, ordinal);
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_read_relocs:  Read a set of relocation offsets for the DLL from
+ * the given file descriptor.
+ *
+ * Parameters:
+ *             dll: DLL handle.
+ *              fd: File descriptor to read from.
+ *      relocs_ptr: Pointer to relocation entry array (dynamically allocated).
+ *     nrelocs_ptr: Pointer to relocation entry count.
+ * Return value:
+ *     Positive if relocations were read successfully.
+ *     Zero if the end of the relocation table was reached.
+ *     Negative if an error cocurred.
+ * Notes:
+ *     - *relocs_ptr and *nrelocs_ptr must be initialized to NULL and 0,
+ *       respectively, before the first call; they will be updated with
+ *       each call.
+ *     - On error, errno is set appropriately.
+ */
+
+static int w32dll_read_relocs(W32DLLHandle dll, int fd,
+                              uint32_t **relocs_ptr, int *nrelocs_ptr)
+{
+    uint32_t base, size, *new_relocs;
+    int index;
+
+    if (read(fd, &base, 4) != 4
+     || read(fd, &size, 4) != 4
+     || (size > 0 && size < 8)
+    ) {
+        free(*relocs_ptr);
+        *relocs_ptr = NULL;
+        *nrelocs_ptr = 0;
+        errno = ENOEXEC;
+        return -1;
+    }
+    if (!size)
+        return 0;
+    if (size <= 8)  // Technically == works too, but play it safe
+        return 1;
+    size = (size-8) / 2;  // Number of entries in this group
+    index = *nrelocs_ptr;
+    new_relocs = realloc(*relocs_ptr,
+                         sizeof(**relocs_ptr) * (*nrelocs_ptr + size));
+    if (!new_relocs)
+        goto err_noexec;
+    *relocs_ptr = new_relocs;
+    *nrelocs_ptr += size;
+    while (size > 0) {
+        uint16_t buf[1000];
+        int toread, i;
+        toread = size;
+        if (toread > sizeof(buf)/2)
+            toread = sizeof(buf)/2;
+        if (read(fd, buf, toread*2) != toread*2)
+            goto err_noexec;
+        for (i = 0; i < toread; i++) {
+            if (buf[i]>>12 == 3) {
+                (*relocs_ptr)[index++] = dll->extheader.image_base
+                                       + base + (buf[i] & 0xFFF);
+            } else {
+                (*nrelocs_ptr)--;
+            }
+        }
+        size -= toread;
+    }
+    return 1;
+
+  err_noexec:
+    {
+        int errno_save = errno;
+        free(*relocs_ptr);
+        *relocs_ptr = NULL;
+        *nrelocs_ptr = 0;
+        errno = errno_save;
+        return -1;
+    }
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_relocate:  Perform relocations on the loaded DLL.
+ *
+ * Parameters:
+ *         dll: DLL handle with all sections loaded.
+ *      relocs: Array of virtual addresses to be relocated.
+ *     nrelocs: Number of relocations.
+ * Return value:
+ *     None.
+ */
+
+#include <stdio.h>
+static void w32dll_relocate(W32DLLHandle dll, uint32_t *relocs, int nrelocs)
+{
+    int i;
+
+    for (i = 0; i < nrelocs; i++) {
+        uint32_t *addr = w32dll_relocate_addr(dll, relocs[i]);
+        if (addr)
+            *addr = (uint32_t)w32dll_relocate_addr(dll, *addr);
+    }
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_relocate_addr:  Relocate a single address.
+ *
+ * Parameters:
+ *      dll: DLL handle.
+ *     addr: Address to relocate.
+ * Return value:
+ *     The relocated address, or NULL if the address is not in a loaded
+ *     section.
+ */
+
+static void *w32dll_relocate_addr(W32DLLHandle dll, uint32_t addr)
+{
+    int i;
+
+    for (i = 0; i < dll->nsections; i++) {
+        if (addr >= dll->sections[i].origbase
+         && addr <  dll->sections[i].origbase + dll->sections[i].origsize
+        ) {
+            return (uint8_t *)dll->sections[i].base
+                   + (addr - dll->sections[i].origbase);
+        }
+    }
+    return NULL;
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_read_asciiz:  Read a null-terminated string from the given file
+ * descriptor.
+ *
+ * Parameters:
+ *     fd: File descriptor to read from.
+ * Return value:
+ *     String read in (allocated with malloc()), or NULL on error.
+ * Notes:
+ *     On error, errno is set appropriately.
+ */
+
+static char *w32dll_read_asciiz(int fd)
+{
+    char *str = NULL;
+    int size = 0, len = 0;
+
+    do {
+        if (len >= size) {
+            char *newstr;
+            size = len+100;
+            newstr = realloc(str, size);
+            if (!newstr) {
+                int errno_save = errno;
+                free(str);
+                errno = errno_save;
+                return NULL;
+            }
+            str = newstr;
+        }
+        if (read(fd, str+len, 1) != 1) {
+            free(str);
+            errno = ENOEXEC;
+            return NULL;
+        }
+        len++;
+    } while (str[len-1] != 0);
+    return str;
+}
+
+/*************************************************************************/
+
+/**
+ * w32dll_init_fs:  Set up the FS segment register to point to a page of
+ * data (empty except for the linear address pointer at 0x18).
+ *
+ * Parameters:
+ *     None.
+ * Return value:
+ *     Nonzero on success, zero on failure.
+ * Notes:
+ *     On error, errno is set appropriately.
+ */
+
+#include <asm/unistd.h>
+#include <asm/ldt.h>
+// This doesn't work, because of PIC:
+//static _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount);
+static int modify_ldt(int func, void *ptr, unsigned long bytecount)
+{
+    long res;
+#if ARCH_X86_64
+    __asm__ volatile ("syscall"
+                      : "=a" (res)
+                      : "0" (__NR_modify_ldt), "D" ((long)(func)),
+                        "S" ((long)(ptr)), "d" ((long)(bytecount))
+                      : "memory");
+#else  // ARCH_X86_32
+    __asm__ volatile ("push %%ebx; mov %%esi, %%ebx; int $0x80; pop %%ebx"
+                      : "=a" (res)
+                      : "0" (__NR_modify_ldt), "S" ((long)(func)),
+                        "c" ((long)(ptr)), "d" ((long)(bytecount))
+                      : "memory");
+#endif
+    /* Errors are from -1 to -128, according to <asm/unistd.h> */
+    if ((res & 0xFFFFFF80UL) == 0xFFFFFF80UL) {
+        errno = -res & 0xFF;
+        res = (unsigned long)-1;
+    }
+    return (int)res;
+}
+
+static int w32dll_init_fs(void)
+{
+    void *base;
+    int segment;
+    struct user_desc ldt;
+
+    base = mmap(NULL, GETPAGESIZE(), PROT_READ | PROT_WRITE,
+                MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
+    if (base == MAP_FAILED) {
+        return 0;
+    }
+    *(uint32_t *)((uint8_t *)base + 0x18) = (uint32_t)(uintptr_t)base;
+
+    memset(&ldt, 0, sizeof(ldt)); 
+    /* Pick a random number that's hopefully unused.  How does one
+     * determine which segment numbers are in use? */
+    ldt.entry_number = 172;
+    ldt.base_addr = (long)base;
+    ldt.limit = GETPAGESIZE();
+    ldt.seg_32bit = 1;
+    ldt.read_exec_only = 0;
+    ldt.seg_not_present = 0;
+    ldt.contents = MODIFY_LDT_CONTENTS_DATA;
+    ldt.limit_in_pages = 0;
+    ldt.seg_not_present = 0;
+    ldt.useable = 1;
+    if (modify_ldt(17, &ldt, sizeof(ldt)) != 0) {
+        int errno_save = errno;
+        munmap(base, GETPAGESIZE());
+        errno = errno_save;
+        return 0;
+    }
+    segment = ldt.entry_number;
+
+    /* Bit 2: 1 == use LDT; bits 1-0: 3 == privilege level 3 */
+    __asm__("movw %%ax,%%fs" : : "a" (segment<<3 | 1<<2 | 3));
+    return 1;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int main(int ac, char **av)
+{
+    W32DLLHandle dll;
+
+    if (ac < 2 || strcmp(av[1], "-h") == 0 || strcmp(av[1], "--help") == 0) {
+        fprintf(stderr, "Usage: %s file.dll [procname | =ordinal]\n", av[0]);
+        return -1;
+    }
+    dll = w32dll_load(av[1], 1);
+    if (!dll) {
+        perror(av[1]);
+        return 1;
+    }
+    if (ac >= 3) {
+        int i;
+        void *(*func)(void);
+        void ***codec, **functable, ***vid, **vidtable, ***aud, **audtable;
+        WINAPI void *(*init)(int, int);
+        WINAPI void *(*fini)(void);
+        WINAPI void *(*getvid)(void);
+        WINAPI void *(*getaud)(void);
+        static char buf[0x14000], buf2[720*480*4], buf2a[0x800], buf3[0x2000];
+        struct { int dataset; void *workbuf; struct {uint8_t w8, h8, f02, f03; int ofs;} *inparam; void *inbuf; struct {int stride; void *outbuf;} *outparam;} vidparam;
+        void *bufptr = buf;
+        struct { int flag; char *buffer; } audparam;
+        int fd = open("/scratch/pv3/060428-192352-720x480i.dv", O_RDONLY);
+        read(fd, buf, 0x14000);
+        close(fd);
+        if (av[2][0] == '=')
+            func = w32dll_lookup_by_ordinal(dll, strtoul(av[2]+1,NULL,0));
+        else
+            func = w32dll_lookup_by_name(dll, av[2]);
+        if (!func) {
+            perror(av[2]);
+            w32dll_unload(dll);
+            return 2;
+        }
+        printf("%s: %p\n", av[2], func);
+        codec = func();
+        functable = *codec;
+        printf("--> %p [%p %p %p %p...]\n", codec,
+               functable[0], functable[1], functable[2], functable[3]);
+        init = functable[0];
+        fini = functable[1];
+        getvid = functable[2];
+        getaud = functable[3];
+        printf("calling init...\n");
+        //(*init)(4, 2);
+        asm("push $2; push $4; call *%0" : : "r" (init), "c" (codec));
+        printf("...done!\n");
+        printf("calling getvid...\n");
+        asm("call *%1" : "=a" (vid) : "r" (getvid), "c" (codec));
+        vidtable = *vid;
+        printf("...done! (%p -> %p %p ... %p ...)\n", aud,
+               vidtable[0], vidtable[1], vidtable[5]);
+        memset(&vidparam, 0, sizeof(vidparam));
+        vidparam.dataset = 0;
+        vidparam.workbuf = buf2a;
+        vidparam.inparam = calloc(sizeof(*vidparam.inparam), 1);
+        vidparam.inparam->w8 = buf[4];
+        vidparam.inparam->h8 = buf[5];
+        vidparam.inparam->ofs = 0;
+        vidparam.inbuf = &bufptr;
+        vidparam.outparam = malloc(sizeof(*vidparam.outparam));
+        vidparam.outparam->stride = (buf[4]*8)*2;
+        vidparam.outparam->outbuf = buf2;
+        printf("calling video_decode...\n");  // 10013830
+        asm("push %2; call *%1"
+            : "=a" (i)
+            : "r" (vidtable[5]), "r" (&vidparam), "c" (vid));
+        printf("...done! (%d)\n", i);
+        printf("and again...\n");
+        vidparam.dataset = 1;
+        asm("push %2; call *%1"
+            : "=a" (i)
+            : "r" (vidtable[5]), "r" (&vidparam), "c" (vid));
+        printf("...done! (%d)\n", i);
+        printf("calling getaud...\n");
+        asm("call *%1" : "=a" (aud) : "r" (getaud), "c" (codec));
+        audtable = *aud;
+        printf("...done! (%p -> %p %p %p ...)\n", aud,
+               audtable[0], audtable[1], audtable[2]);
+        audparam.flag = 0;
+        audparam.buffer = buf;
+        *(void **)(buf3+24) = buf3+32;
+        printf("calling audio_decode...\n");  // 10013830
+        asm("push %3; push %2; call *%1"
+            : "=a" (i)
+            : "r" (audtable[1]), "r" (&audparam), "r" (buf3), "c" (aud));
+        printf("...done! (%d)\n", i);
+        fd = open("/scratch/pv3/test.raw", O_WRONLY | O_CREAT | O_TRUNC, 0666);
+        write(fd, buf3, sizeof(buf3));
+        write(fd, buf2, sizeof(buf2));
+        close(fd);
+        printf("calling fini...\n");
+        asm("call *%0" : : "r" (fini), "c" (codec));
+        //(*fini)();
+        printf("...done!\n");
+    }
+    w32dll_unload(dll);
+    return 0;
+}
+
+#endif
+
+/*************************************************************************/
+
+/*
+ * Local variables:
+ *   c-file-style: "stroustrup"
+ *   c-file-offsets: ((case-label . *) (statement-case-intro . *))
+ *   indent-tabs-mode: nil
+ * End:
+ *
+ * vim: expandtab shiftwidth=4:
+ */
diff -urN ffmpeg-3.2.1-orig/libavcodec/w32dll.h ffmpeg-3.2.1/libavcodec/w32dll.h
--- ffmpeg-3.2.1-orig/libavcodec/w32dll.h	1970-01-01 09:00:00 +0900
+++ ffmpeg-3.2.1/libavcodec/w32dll.h	2016-12-06 15:02:29 +0900
@@ -0,0 +1,107 @@
+/*
+ * w32dll.h -- w32dll.c interface declaration
+ * Written by Andrew Church <achurch@achurch.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef W32DLL_H
+#define W32DLL_H
+
+/*************************************************************************/
+
+/* DLL handle type (opaque) */
+struct w32dllhandle_;
+typedef struct w32dllhandle_ *W32DLLHandle;
+
+/* WINAPI and CALLBACK calling format definitions, used by some DLLs. */
+#if defined(__GNUC__)
+# define WINAPI __attribute__((stdcall))
+#else
+# define WINAPI __stdcall
+#endif
+#define CALLBACK WINAPI
+
+/*************************************************************************/
+
+/**
+ * w32dll_load:  Load the given DLL file into memory, and return a handle
+ * to it.
+ *
+ * Parameters:
+ *       path: DLL file pathname.
+ *     compat: If nonzero, adds a memory mapping for the entire DLL to
+ *             accommodate misbehaving DLLs that access memory outside the
+ *             registered sections.
+ * Return value:
+ *     DLL handle (nonzero), or zero on error.
+ * Side effects:
+ *     Sets errno to an appropriate value on error, including ENOEXEC if
+ *     the file is not recognized as a Win32 DLL file or is corrupt or
+ *     truncated, or ETXTBSY if the DLL's DllMain() function returns an
+ *     error.  On successful return, errno is undefined.
+ */
+extern W32DLLHandle w32dll_load(const char *path, int compat);
+
+/**
+ * w32dll_unload:  Unload the given DLL from memory.  Does nothing if the
+ * given handle is zero.
+ *
+ * Parameters:
+ *     dll: DLL handle.
+ * Return value:
+ *     None.
+ */
+extern void w32dll_unload(W32DLLHandle dll);
+
+/**
+ * w32dll_lookup_by_name:  Look up the address of an exported function in
+ * the given DLL, using the function's name.
+ *
+ * Parameters:
+ *      dll: DLL handle.
+ *     name: Function name.
+ * Return value:
+ *     Function address, or NULL on error.
+ * Side effects:
+ *     Sets errno to one of the following values on error:
+ *         EINVAL: `dll' or `name' was invalid.
+ *         ENOENT: The requested function does not exist.
+ *     On successful return, errno is undefined.
+ */
+extern void *w32dll_lookup_by_name(W32DLLHandle dll, const char *name);
+
+/**
+ * w32dll_lookup_by_ordinal:  Look up the address of an exported function
+ * in the given DLL, using the function's ordinal value.
+ *
+ * Parameters:
+ *         dll: DLL handle.
+ *     ordinal: Function ordinal.
+ * Return value:
+ *     Function address, or NULL on error.
+ * Side effects:
+ *     Sets errno to one of the following values on error:
+ *         EINVAL: `dll' was invalid.
+ *         ENOENT: The requested function does not exist.
+ *     On successful return, errno is undefined.
+ */
+extern void *w32dll_lookup_by_ordinal(W32DLLHandle dll, uint32_t ordinal);
+
+/*************************************************************************/
+
+#endif  /* W32DLL_H */
diff -urN ffmpeg-3.2.1-orig/libavformat/Makefile ffmpeg-3.2.1/libavformat/Makefile
--- ffmpeg-3.2.1-orig/libavformat/Makefile	2016-10-28 01:17:40 +0900
+++ ffmpeg-3.2.1/libavformat/Makefile	2016-12-06 15:02:29 +0900
@@ -390,6 +390,7 @@
 OBJS-$(CONFIG_PCM_U8_MUXER)              += pcmenc.o rawenc.o
 OBJS-$(CONFIG_PJS_DEMUXER)               += pjsdec.o subtitles.o
 OBJS-$(CONFIG_PMP_DEMUXER)               += pmpdec.o
+OBJS-$(CONFIG_PV3_DEMUXER)               += pv3.o
 OBJS-$(CONFIG_PVA_DEMUXER)               += pva.o
 OBJS-$(CONFIG_PVF_DEMUXER)               += pvfdec.o pcm.o
 OBJS-$(CONFIG_QCP_DEMUXER)               += qcp.o
diff -urN ffmpeg-3.2.1-orig/libavformat/allformats.c ffmpeg-3.2.1/libavformat/allformats.c
--- ffmpeg-3.2.1-orig/libavformat/allformats.c	2016-10-28 01:17:40 +0900
+++ ffmpeg-3.2.1/libavformat/allformats.c	2016-12-06 15:02:29 +0900
@@ -253,6 +253,7 @@
     REGISTER_DEMUXER (PJS,              pjs);
     REGISTER_DEMUXER (PMP,              pmp);
     REGISTER_MUXER   (PSP,              psp);
+    REGISTER_DEMUXER (PV3,              pv3);
     REGISTER_DEMUXER (PVA,              pva);
     REGISTER_DEMUXER (PVF,              pvf);
     REGISTER_DEMUXER (QCP,              qcp);
diff -urN ffmpeg-3.2.1-orig/libavformat/pv3.c ffmpeg-3.2.1/libavformat/pv3.c
--- ffmpeg-3.2.1-orig/libavformat/pv3.c	1970-01-01 09:00:00 +0900
+++ ffmpeg-3.2.1/libavformat/pv3.c	2016-12-06 15:02:29 +0900
@@ -0,0 +1,304 @@
+/*
+ * Earth Soft PV3 demuxer
+ * Copyright (c) 2015 Andrew Church (achurch@achurch.org)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Earth Soft PV3 demuxer
+ *
+ * Technical details (in Japanese):
+ *    http://earthsoft.jp/PV/tech-file.html
+ *    http://earthsoft.jp/PV/tech-codec.html
+ */
+
+#include "avformat.h"
+#include "internal.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libavutil/intreadwrite.h"
+
+typedef struct PV3DemuxContext {
+    AVClass *class;
+
+    /* Option values */
+    char *index_file;       ///< Path of *.dvi file for stream
+
+    /* Global stream parameters */
+    int fps;                ///< Frames per second of video stream (30 or 60)
+    int audio_rate;         ///< Audio playback rate (samples per second)
+    int64_t audio_start;    ///< PTS of first audio sample
+
+    /* Data for the current packet */
+    int frame_num;          ///< Zero-based video frame index of current packet
+    enum {
+        PV3_READ_HEADER,
+        PV3_READ_AUDIO,
+        PV3_READ_VIDEO,
+    } read_state;
+    uint8_t header[512];    ///< Packet header
+} PV3DemuxContext;
+
+static int probe(AVProbeData *p)
+{
+    const uint8_t *b = p->buf;
+
+    if (b[0] == 'P' && b[1] == 'V' && b[2] == '3' && b[3] == 2) {
+        return AVPROBE_SCORE_MAX;
+    }
+    return 0;
+}
+
+static void read_index(AVFormatContext *s)
+{
+    PV3DemuxContext *pv3 = s->priv_data;
+    AVStream *vst = s->streams[0];
+    AVStream *ast = s->streams[1];
+    AVIOContext *pb;
+    unsigned char entry[16];
+    int ret;
+
+    if ((ret = avio_open(&pb, pv3->index_file, AVIO_FLAG_READ)) < 0) {
+        av_log(s, AV_LOG_WARNING, "Could not open index file %s\n",
+               pv3->index_file);
+        return;
+    }
+
+    vst->duration = 0;
+    ast->duration = 0;
+    while (avio_read(pb, entry, 16) == 16) {
+        uint64_t pos = (uint64_t)AV_RB32(entry) << 12;
+        uint32_t size = AV_RB16(entry + 4) << 12;
+        if ((ret = av_add_index_entry(vst, pos, vst->duration, size, 0,
+                                      AVINDEX_KEYFRAME)) < 0) {
+            av_log(s, AV_LOG_WARNING, "Error adding index entry for frame %d",
+                   (int)vst->duration);
+            break;
+        }
+        vst->duration++;
+        ast->duration += AV_RB16(entry + 12);
+    }
+
+    avio_close(pb);
+}
+
+static int read_header(AVFormatContext *s)
+{
+    PV3DemuxContext *pv3 = s->priv_data;
+    AVIOContext *pb = s->pb;
+    AVStream *vst, *ast;
+    int ret, i;
+
+    vst = avformat_new_stream(s, NULL);
+    if (!vst)
+        return AVERROR(ENOMEM);
+    vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+    vst->codec->codec_id = AV_CODEC_ID_PV3VIDEO;
+    vst->codec->extradata_size = 256;
+    vst->codec->extradata = av_malloc(vst->codec->extradata_size);
+    if (!vst->codec->extradata)
+        return AVERROR(ENOMEM);
+
+    ast = avformat_new_stream(s, NULL);
+    if (!ast)
+        return AVERROR(ENOMEM);
+    ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+    ast->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
+    ast->codec->codec_tag = 0;
+    ast->codec->channels = 2;
+    ast->codec->channel_layout = AV_CH_LAYOUT_STEREO;
+
+    vst->codec->codec_tag = avio_rb32(pb);
+    vst->codec->pix_fmt = AV_PIX_FMT_YUYV422;
+    vst->codec->width = avio_r8(pb) * 16;
+    vst->codec->height = avio_r8(pb) * 8;
+    if (avio_r8(pb) & 1) {
+        pv3->fps = 60;
+        vst->codec->field_order = AV_FIELD_PROGRESSIVE;
+    } else {
+        pv3->fps = 30;
+        if (vst->codec->height == 480) {
+            vst->codec->field_order = AV_FIELD_BB;
+        } else {
+            vst->codec->field_order = AV_FIELD_TT;
+        }
+    }
+    avpriv_set_pts_info(vst, 64, 1001, pv3->fps * 1000);
+    vst->avg_frame_rate = av_inv_q(vst->time_base);
+    avio_skip(pb, 256-7);
+
+    for (i = 0; i < 128; i++) {
+        ((uint16_t *)vst->codec->extradata)[i] = avio_rb16(pb);
+    }
+    avio_skip(pb, 16384-512);
+
+    if ((ret = avio_read(pb, pv3->header, 512)) < 0)
+        return ret;
+    pv3->audio_start = AV_RB48(pv3->header);
+    ast->codec->sample_rate = AV_RB32(pv3->header + 8);
+    pv3->audio_rate = ast->codec->sample_rate;
+    avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
+    vst->sample_aspect_ratio.num =
+        AV_RB16(pv3->header + 256) * vst->codec->height;
+    vst->sample_aspect_ratio.den =
+        AV_RB16(pv3->header + 258) * vst->codec->width;
+
+    if (!pv3->index_file && s->filename) {
+        int len = strlen(s->filename);
+        if (len >= 3 && strcmp(s->filename + len - 3, ".dv") == 0) {
+            pv3->index_file = av_malloc(strlen(s->filename) + 2);
+            if (!pv3->index_file) {
+                av_log(s, AV_LOG_ERROR,
+                       "Out of memory generating index file pathname\n");
+            } else {
+                memcpy(pv3->index_file, s->filename, len);
+                pv3->index_file[len] = 'i';
+                pv3->index_file[len+1] = '\0';
+            }
+        }
+    }
+
+    if (pv3->index_file) {
+        read_index(s);
+    }
+
+    pv3->frame_num = 0;
+    pv3->read_state = PV3_READ_AUDIO;
+    return 0;
+}
+
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    PV3DemuxContext *pv3 = s->priv_data;
+    AVIOContext *pb = s->pb;
+    int ret;
+
+    switch (pv3->read_state) {
+    case PV3_READ_HEADER:
+        if ((ret = avio_read(pb, pv3->header, 512)) < 0)
+            return ret;
+        pv3->read_state = PV3_READ_AUDIO;
+        // fall through
+
+    case PV3_READ_AUDIO: {
+        int audio_len = AV_RB16(pv3->header + 6);
+        int audio_size = audio_len * 4;
+        int video_offset = (512 + audio_size + 4095) / 4096 * 4096;
+        if ((ret = av_get_packet(pb, pkt, audio_size)) < 0)
+            return ret;
+        pkt->stream_index = 1;
+        pkt->pts = AV_RB48(pv3->header) - pv3->audio_start;
+        avio_skip(pb, video_offset - (512 + audio_size));
+        pv3->read_state = PV3_READ_VIDEO;
+        return 0;
+    }
+
+    case PV3_READ_VIDEO: {
+        uint32_t audio_len, video_offset, video_size;
+        audio_len = AV_RB16(pv3->header + 6);
+        video_offset = (512 + audio_len*4 + 4095) / 4096 * 4096;
+        video_size = AV_RB32(pv3->header + 384) + AV_RB32(pv3->header + 388);
+        if (s->streams[0]->codec->field_order != AV_FIELD_PROGRESSIVE) {
+            video_size += AV_RB32(pv3->header + 392)
+                       +  AV_RB32(pv3->header + 396);
+        }
+        video_size = (video_size + 4095) / 4096 * 4096;
+
+        if ((ret = av_new_packet(pkt, video_offset)) < 0)
+            return ret;
+        pkt->pos = avio_tell(pb) - video_offset;
+        pkt->stream_index = 0;
+        pkt->pts = pv3->frame_num;
+        memcpy(pkt->data, pv3->header, 512);
+        memset(pkt->data + 512, 0, video_offset - 512);
+
+        if ((ret = av_append_packet(pb, pkt, video_size)) < 0)
+            return ret;
+
+        pv3->frame_num++;
+        pv3->read_state = PV3_READ_HEADER;
+        return 0;
+    }
+    }
+
+    av_assert1(!"unreachable");
+    return -1;
+}
+
+static int read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
+{
+    PV3DemuxContext *pv3 = s->priv_data;
+    AVStream *vst = s->streams[0];
+    int frame, index_entry;
+
+    if (!s->pb->seekable)
+        return -1;
+
+    if (stream_index == 0) {  // video
+        frame = timestamp;
+    } else {  // audio
+        int64_t sample = timestamp - pv3->audio_start;
+        frame = (sample * pv3->fps * 1000) / (pv3->audio_rate * 1001);
+    }
+
+    if (vst->duration > 0) {
+        if (frame >= vst->duration)
+            return AVERROR_EOF;
+        index_entry = av_index_search_timestamp(vst, frame, AVSEEK_FLAG_ANY);
+        if (index_entry < 0)
+            return -1;
+        if (avio_seek(s->pb, vst->index_entries[index_entry].pos, SEEK_SET) < 0)
+            return -1;
+    } else {
+        if (frame != 0)
+            return -1;
+        if (avio_seek(s->pb, 16384, SEEK_SET) < 0)
+            return -1;
+    }
+
+    pv3->frame_num = frame;
+    pv3->read_state = PV3_READ_HEADER;
+    return 0;
+}
+
+static const AVOption options[] = {
+    { "index_file", "Path of .dvi file", offsetof(PV3DemuxContext, index_file),
+      AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
+    { NULL }
+};
+
+static const AVClass pv3_demuxer_class = {
+    .class_name = "PV3 demuxer",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_pv3_demuxer = {
+    .name           = "pv3",
+    .long_name      = NULL_IF_CONFIG_SMALL("Earth Soft PV3"),
+    .priv_data_size = sizeof(PV3DemuxContext),
+    .priv_class     = &pv3_demuxer_class,
+    .read_probe     = probe,
+    .read_header    = read_header,
+    .read_packet    = read_packet,
+    .read_seek      = read_seek,
+};
