Skip to content

Instantly share code, notes, and snippets.

@qyot27
Last active December 18, 2015 13:59
Show Gist options
  • Save qyot27/5794294 to your computer and use it in GitHub Desktop.
Save qyot27/5794294 to your computer and use it in GitHub Desktop.
Support for AvxSynth
From b60d96ed08a71966f3e78fde7568c1eebf121e8d Mon Sep 17 00:00:00 2001
From: Stephen Hutchinson <[email protected]>
Date: Wed, 24 Apr 2013 10:04:56 -0400
Subject: [PATCH 1/3] Add AvxSynth plugin support.
---
AvxSynth/GNUmakefile | 63 ++
AvxSynth/LICENSE | 49 ++
AvxSynth/README | 181 ++++++
AvxSynth/audio_output.cpp | 137 ++++
AvxSynth/audio_output.h | 35 ++
AvxSynth/avxplugin.h | 763 +++++++++++++++++++++++
AvxSynth/configure | 314 ++++++++++
AvxSynth/libavsmash_source.cpp | 538 ++++++++++++++++
AvxSynth/libavsmash_source.h | 117 ++++
AvxSynth/lsmashsource.cpp | 88 +++
AvxSynth/lsmashsource.h | 35 ++
AvxSynth/lwlibav_source.cpp | 310 +++++++++
AvxSynth/lwlibav_source.h | 93 +++
AvxSynth/video_output.cpp | 673 ++++++++++++++++++++
AvxSynth/video_output.h | 87 +++
AvxSynth/windowsPorts/WinDefLinux.h | 20 +
AvxSynth/windowsPorts/WinNTLinux.h | 74 +++
AvxSynth/windowsPorts/basicDataTypeConversions.h | 85 +++
AvxSynth/windowsPorts/excptLinux.h | 21 +
AvxSynth/windowsPorts/windows2linux.h | 77 +++
20 files changed, 3760 insertions(+)
create mode 100644 AvxSynth/GNUmakefile
create mode 100644 AvxSynth/LICENSE
create mode 100644 AvxSynth/README
create mode 100644 AvxSynth/audio_output.cpp
create mode 100644 AvxSynth/audio_output.h
create mode 100644 AvxSynth/avxplugin.h
create mode 100755 AvxSynth/configure
create mode 100644 AvxSynth/libavsmash_source.cpp
create mode 100644 AvxSynth/libavsmash_source.h
create mode 100644 AvxSynth/lsmashsource.cpp
create mode 100644 AvxSynth/lsmashsource.h
create mode 100644 AvxSynth/lwlibav_source.cpp
create mode 100644 AvxSynth/lwlibav_source.h
create mode 100644 AvxSynth/video_output.cpp
create mode 100644 AvxSynth/video_output.h
create mode 100644 AvxSynth/windowsPorts/WinDefLinux.h
create mode 100644 AvxSynth/windowsPorts/WinNTLinux.h
create mode 100644 AvxSynth/windowsPorts/basicDataTypeConversions.h
create mode 100644 AvxSynth/windowsPorts/excptLinux.h
create mode 100644 AvxSynth/windowsPorts/windows2linux.h
diff --git a/AvxSynth/GNUmakefile b/AvxSynth/GNUmakefile
new file mode 100644
index 0000000..1c71099
--- /dev/null
+++ b/AvxSynth/GNUmakefile
@@ -0,0 +1,63 @@
+#----------------------------------------------------------------------------------------------
+# Makefile for AvxSynth plugins
+#----------------------------------------------------------------------------------------------
+
+include config.mak
+
+vpath %.cpp $(SRCDIR)
+vpath %.c $(SRCDIR)
+vpath %.h $(SRCDIR)
+
+OBJ_SOURCE_CXX = lsmashsource.o video_output.o audio_output.o libavsmash_source.o \
+ lwlibav_source.o
+
+OBJ_SOURCE_C = ../common/utils.o ../common/libavsmash.o ../common/libavsmash_video.o \
+ ../common/libavsmash_audio.o ../common/lwlibav_dec.o \
+ ../common/lwlibav_video.o ../common/resample.o ../common/lwlibav_audio.o \
+ ../common/lwindex.o ../common/video_output.o ../common/audio_output.o
+
+SRC_ALL = $(SRC_SOURCE)
+
+ifneq ($(STRIP),)
+LDFLAGS += -Wl,-s
+endif
+
+.PHONY: all clean distclean dep
+
+all: $(SONAME)
+
+$(SONAME): $(OBJ_SOURCE_CXX) $(OBJ_SOURCE_C)
+ $(LD) $(SOFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+ -@ $(if $(STRIP), $(STRIP) -x $@)
+
+%.o: %.cpp %.c .depend
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+install: all
+ install -d $(DESTDIR)$(libdir)
+ install -m 755 $(SONAME) $(DESTDIR)$(libdir)/$(SONAME)
+ $(if $(SONAME), ln -f -s $(DESTDIR)$(libdir)/$(SONAME) $(DESTDIR)$(libdir)/avxsynth/$(SONAME_LN))
+
+#All objects should be deleted regardless of configure when uninstall/clean/distclean.
+uninstall:
+ $(RM) $(DESTDIR)$(libdir)/$(SONAME) $(DESTDIR)$(libdir)/avxsynth/$(SONAME_LN)
+
+clean:
+ $(RM) $(SONAME) *.o .depend
+
+distclean: clean
+ $(RM) config.*
+
+dep: .depend
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
+
+.depend: config.mak
+ @$(RM) .depend
+ @$(foreach SRC, $(SRC_ALL:%=$(SRCDIR)/%), $(CXX) $(SRC_SOURCE) $(CXXFLAGS) -msse2 -g0 -MT $(SRC:$(SRCDIR)/%.cpp=%.o) -MM >> .depend;)
+ @$(foreach SRC, $(SRC_ALL:%=$(SRCDIR)/%), $(CC) $(SRC_SOURCE) $(CFLAGS) -msse2 -g0 -MT $(SRC:$(SRCDIR)/%.c=%.o) -MM >> .depend;)
+
+config.mak:
+ configure
\ No newline at end of file
diff --git a/AvxSynth/LICENSE b/AvxSynth/LICENSE
new file mode 100644
index 0000000..8a62f8a
--- /dev/null
+++ b/AvxSynth/LICENSE
@@ -0,0 +1,49 @@
+Copyright (C) 2012-2013 L-SMASH Works project
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-----------------------------------------------------------------------------
+
+Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al.
+http://www.avisynth.org
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
+http:www.gnu.org/copyleft/gpl.html .
+
+Linking Avisynth statically or dynamically with other modules is making a
+combined work based on Avisynth. Thus, the terms and conditions of the GNU
+General Public License cover the whole combination.
+
+As a special exception, the copyright holders of Avisynth give you
+permission to link Avisynth with independent modules that communicate with
+Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
+terms of these independent modules, and to copy and distribute the
+resulting combined work under terms of your choice, provided that
+every copy of the combined work is accompanied by a complete copy of
+the source code of Avisynth (the version of Avisynth used to produce the
+combined work), being distributed under the terms of the GNU General
+Public License plus this exception. An independent module is a module
+which is not derived from or based on Avisynth, such as 3rd-party filters,
+import and export plugins, or graphical user interfaces.
diff --git a/AvxSynth/README b/AvxSynth/README
new file mode 100644
index 0000000..d263a4e
--- /dev/null
+++ b/AvxSynth/README
@@ -0,0 +1,181 @@
+[File]
+ libavxlsmashsource.so : A source plugin for AvxSynth
+
+[libavxlsmashsource.so: LSMASHSource]
+ [Functions]
+ [LSMASHVideoSource]
+ LSMASHVideoSource(string source, int track = 0, int threads = 0, int seek_mode = 0, int seek_threshold = 10, bool dr = false)
+ * This function uses libavcodec as video decoder and L-SMASH as demuxer.
+ [Arguments]
+ + source
+ The path of the source file.
+ + track (default : 0)
+ The track number to open in the source file.
+ The value 0 means trying to get the first detected video stream.
+ + threads (default : 0)
+ The number of threads to decode a stream by libavcodec.
+ The value 0 means the number of threads is determined automatically and then the maximum value will be up to 16.
+ + seek_mode (default : 0)
+ How to process when any error occurs during decoding a video frame.
+ - 0 : Normal
+ This mode retries sequential decoding from the next closest RAP up to 3 cycles when any decoding error occurs.
+ If all 3 trial failed, retry sequential decoding from the last RAP by ignoring trivial errors.
+ Still error occurs, then return the last returned frame.
+ - 1 : Unsafe
+ This mode retries sequential decoding from the next closest RAP up to 3 cycles when any fatal decoding error occurs.
+ If all 3 trial failed, then return the last returned frame.
+ - 2 : Aggressive
+ This mode returns the last returned frame when any fatal decoding error occurs.
+ + seek_threshold (default : 10)
+ The threshold to decide whether a decoding starts from the closest RAP to get the requested video frame or doesn't.
+ * RAP is an abbreviation of random accessible point.
+ Let's say
+ - the threshold is T,
+ and
+ - you request to seek the M-th frame called f(M) from the N-th frame called f(N).
+ If M > N and M - N <= T, then
+ the decoder tries to get f(N) by decoding frames from f(M) sequentially.
+ If M < N or M - N > T, then
+ check the closest RAP at the first.
+ After the check, if the closest RAP is identical with the last RAP, do the same as the case M > N and M - N <= T.
+ Otherwise, the decoder tries to get f(N) by decoding frames from the frame which is the closest RAP sequentially.
+ + dr (default : false)
+ Try direct rendering from the video decoder if set to true.
+ The output resolution will be aligned to be mod16-width and mod32-height by assuming two vertical 16x16 macroblock.
+ For H.264 streams, in addition, 2 lines could be added because of the optimized chroma MC.
+ [LSMASHAudioSource]
+ LSMASHAudioSource(string source, int track = 0, bool skip_priming = true, string layout = "", int rate = 0)
+ * This function uses libavcodec as audio decoder and L-SMASH as demuxer.
+ [Arguments]
+ + source
+ The path of the source file.
+ + track (default : 0)
+ The track number to open in the source file.
+ The value 0 means trying to get the first detected audio stream.
+ + skip_priming (default : true)
+ Whether skip priming samples or not.
+ Priming samples is detected from iTunSMPB or the first non-empty edit.
+ If any priming samples, do pre-roll whenever any seek of audio stream occurs.
+ + layout (default : "")
+ Output audio channel layout.
+ If unspecified, audio stream is output to the buffer from the decoder via the resampler at the channel layout
+ which is the first maximum number of channels in audio stream.
+ You can specify channel layout by combination of the name of a channel layout with separator (+) as follows.
+ - the name or mask of a single channel.
+ FL (0x1) = Front Left
+ FR (0x2) = Front Right
+ FC (0x4) = Front Center
+ LFE (0x8) = Low Frequency Effect
+ BL (0x10) = Back Left
+ BR (0x20) = Back Right
+ FLC (0x40) = Front Left of Center
+ FRC (0x80) = Front Right of Center
+ BC (0x100) = Back Center
+ SL (0x200) = Side Left
+ SR (0x400) = Side Right
+ TC (0x800) = Top Center
+ TFL (0x1000) = Top Front Left
+ TFC (0x2000) = Top Front Center
+ TFR (0x4000) = Top Front Right
+ TBL (0x8000) = Top Back Left
+ TBC (0x10000) = Top Back Center
+ TBR (0x20000) = Top Back Right
+ DL (0x20000000) = Stereo Downmixed Left
+ DR (0x40000000) = Stereo Downmixed Right
+ WL (0x80000000) = Wide Left
+ WR (0x100000000) = Wide Right
+ SDL (0x200000000) = Surround Direct Left
+ SDR (0x400000000) = Surround Direct Right
+ LFE2 (0x800000000) = Low Frequency Effect 2
+ $ Example: standard ffmpeg based 5.1ch surround layout : FL+FR+FC+LFE+BL+BR = 0x3f
+ - the name of an usual channel layout.
+ libav | ffmpeg
+ mono = FC | FC
+ stereo = FL+FR | FL+FR
+ 2.1 = FL+FR+LFE | FL+FR+LFE
+ 3.0 = FL+FR+FC | FL+FR+FC
+ 3.0(back) = FL+FR+BC | FL+FR+BC
+ 3.1 = FL+FR+FC+LFE | FL+FR+FC+LFE
+ 4.0 = FL+FR+FC+BC | FL+FR+FC+BC
+ quad = FL+FR+BL+BR | FL+FR+BL+BR
+ quad(side) = FL+FR+SL+SR | FL+FR+SL+SR
+ 5.0 = FL+FR+FC+SL+SR | FL+FR+FC+BL+BR
+ 5.1 = FL+FR+FC+LFE+SL+SR | FL+FR+FC+LFE+BL+BR
+ 6.0 = FL+FR+FC+BC+SL+SR | FL+FR+FC+BC+SL+SR
+ 6.0(front) = FL+FR+FLC+FRC+SL+SR | FL+FR+FLC+FRC+SL+SR
+ hexagonal = FL+FR+FC+BL+BR+BC | FL+FR+FC+BL+BR+BC
+ 6.1 = FL+FR+FC+LFE+BC+SL+SR | FL+FR+FC+LFE+BC+SL+SR
+ 6.1(front) = FL+FR+LFE+FLC+FRC+SL+SR | FL+FR+LFE+FLC+FRC+SL+SR
+ 7.0 = FL+FR+FC+BL+BR+SL+SR | FL+FR+FC+BL+BR+SL+SR
+ 7.0(front) = FL+FR+FC+FLC+FRC+SL+SR | FL+FR+FC+FLC+FRC+SL+SR
+ 7.1 = FL+FR+FC+LFE+BL+BR+SL+SR | FL+FR+FC+LFE+BL+BR+SL+SR
+ 7.1(wide) = FL+FR+FC+LFE+FLC+FRC+SL+SR | FL+FR+FC+LFE+BL+BR+FLC+FRC
+ 7.1(wide-side) = N/A | FL+FR+FC+LFE+FLC+FRC+SL+SR
+ octagonal = FL+FR+FC+BL+BR+BC+SL+SR | FL+FR+FC+BL+BR+BC+SL+SR
+ downmix = DL+DR | DL+DR
+ - a number of channels.
+ libav | ffmpeg
+ 1 = FC | FC
+ 2 = FL+FR | FL+FR
+ 3 = FL+FR+FC | FL+FR+LFE
+ 4 = FL+FR+BL+BR | FL+FR+FC+BC
+ 5 = FL+FR+FC+SL+SR | FL+FR+FC+BL+BR
+ 6 = FL+FR+FC+LFE+SL+SR | FL+FR+FC+LFE+BL+BR
+ 7 = FL+FR+FC+LFE+BC+SL+SR | FL+FR+FC+LFE+BC+SL+SR
+ 8 = FL+FR+FC+LFE+BL+BR+SL+SR | FL+FR+FC+LFE+BL+BR+SL+SR
+ Note: the above listed notations are the present things.
+ In the future, they might be changed.
+ + rate (default : 0)
+ Audio sampling rate or sampling frequency in units of Hz.
+ The defaut value 0 means audio stream is output to the buffer via the resampler at the maximum sampling rate in audio stream.
+ Otherwise, audio stream is output to the buffer via the resampler at specified sampling rate.
+ [LWLibavVideoSource]
+ LWLibavVideoSource(string source, int stream_index = -1, int threads = 0, bool cache = true,
+ int seek_mode = 0, int seek_threshold = 10, bool dr = false,
+ bool repeat = false, int dominance = 1)
+ * This function uses libavcodec as video decoder and libavformat as demuxer.
+ [Arguments]
+ + source
+ The path of the source file.
+ + stream_index (default : -1)
+ The stream index to open in the source file.
+ The value -1 means trying to get the video stream which has the largest resolution.
+ + threads (default : 0)
+ Same as 'threads' of LSMASHVideoSource().
+ + cache (default : true)
+ Create the index file (.lwi) to the same directory as the source file if set to true.
+ The index file avoids parsing all frames in the source file at the next or later access.
+ Parsing all frames is very important for frame accurate seek.
+ + seek_mode (default : 0)
+ Same as 'seek_mode' of LSMASHVideoSource().
+ + seek_threshold (default : 10)
+ Same as 'seek_threshold' of LSMASHVideoSource().
+ + dr (default : false)
+ Same as 'dr' of LSMASHVideoSource().
+ + repeat (default : false)
+ Reconstruct frames by the flags specified in video stream and then treat all frames as interlaced if set to true and usable.
+ If set to false, video frames consisting of two separated field coded pictures are displayed twice consecutively.
+ + dominance : (default : 1)
+ Which field, top or bottom, is displayed first.
+ - 0 : reserved
+ - 1 : TFF i.e. Top -> Bottom
+ - 2 : BFF i.e. Bottom -> Top
+ This option is enabled only if 'repeat' is set to true.
+ [LWLibavAudioSource]
+ LWLibavAudioSource(string source, int stream_index = -1, bool cache = true, bool av_sync = false, string layout = "", int rate = 0)
+ * This function uses libavcodec as audio decoder and libavformat as demuxer.
+ * If audio stream can be coded as lossy, do pre-roll whenever any seek of audio stream occurs.
+ [Arguments]
+ + source
+ The path of the source file.
+ + stream_index (default : -1)
+ The stream index to open in the source file.
+ The value -1 means trying to get the first detected audio stream.
+ + cache (default : true)
+ Same as 'cache' of LWLibavVideoSource().
+ + av_sync (default : false)
+ Try Audio/Visual synchronization at the first video frame of the video stream activated in the index file if set to true.
+ + layout (defalut : "")
+ Same as 'layout' of LSMASHAudioSource().
+ + rate (default : 0)
+ Same as 'rate' of LSMASHAudioSource().
diff --git a/AvxSynth/audio_output.cpp b/AvxSynth/audio_output.cpp
new file mode 100644
index 0000000..1de3659
--- /dev/null
+++ b/AvxSynth/audio_output.cpp
@@ -0,0 +1,137 @@
+/*****************************************************************************
+ * audio_output.cpp
+ *****************************************************************************
+ * Copyright (C) 2012-2013 L-SMASH Works project
+ *
+ * Authors: Yusuke Nakamura <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *****************************************************************************/
+
+/* This file is available under an ISC license.
+ * However, when distributing its binary file, it will be under LGPL or GPL. */
+
+#include "lsmashsource.h"
+
+extern "C"
+{
+#include <libavcodec/avcodec.h>
+#include <libavresample/avresample.h>
+#include <libavutil/opt.h>
+}
+
+#include "audio_output.h"
+
+static inline enum AVSampleFormat as_decide_audio_output_sample_format( enum AVSampleFormat input_sample_format )
+{
+ /* Avisynth doesn't support IEEE double precision floating point format. */
+ switch( input_sample_format )
+ {
+ case AV_SAMPLE_FMT_U8 :
+ case AV_SAMPLE_FMT_U8P :
+ return AV_SAMPLE_FMT_U8;
+ case AV_SAMPLE_FMT_S16 :
+ case AV_SAMPLE_FMT_S16P :
+ return AV_SAMPLE_FMT_S16;
+ case AV_SAMPLE_FMT_S32 :
+ case AV_SAMPLE_FMT_S32P :
+ return AV_SAMPLE_FMT_S32;
+ default :
+ return AV_SAMPLE_FMT_FLT;
+ }
+}
+
+void as_setup_audio_rendering
+(
+ lw_audio_output_handler_t *aohp,
+ AVCodecContext *ctx,
+ avxsynth::VideoInfo *vi,
+ avxsynth::IScriptEnvironment *env,
+ const char *filter_name,
+ uint64_t channel_layout,
+ int sample_rate
+)
+{
+ /* Channel layout. */
+ if( ctx->channel_layout == 0 )
+ ctx->channel_layout = av_get_default_channel_layout( ctx->channels );
+ if( channel_layout != 0 )
+ aohp->output_channel_layout = channel_layout;
+ /* Sample rate. */
+ if( sample_rate > 0 )
+ aohp->output_sample_rate = sample_rate;
+ /* Decide output Bits Per Sample. */
+ aohp->output_sample_format = as_decide_audio_output_sample_format( aohp->output_sample_format );
+ if( aohp->output_sample_format == AV_SAMPLE_FMT_S32
+ && (aohp->output_bits_per_sample == 0 || aohp->output_bits_per_sample == 24) )
+ {
+ /* 24bit signed integer output */
+ aohp->s24_output = 1;
+ aohp->output_bits_per_sample = 24;
+ }
+ else
+ aohp->output_bits_per_sample = av_get_bytes_per_sample( aohp->output_sample_format ) * 8;
+ /* Set up the number of planes and the block alignment of decoded and output data. */
+ int input_channels = av_get_channel_layout_nb_channels( ctx->channel_layout );
+ if( av_sample_fmt_is_planar( ctx->sample_fmt ) )
+ {
+ aohp->input_planes = input_channels;
+ aohp->input_block_align = av_get_bytes_per_sample( ctx->sample_fmt );
+ }
+ else
+ {
+ aohp->input_planes = 1;
+ aohp->input_block_align = av_get_bytes_per_sample( ctx->sample_fmt ) * input_channels;
+ }
+ int output_channels = av_get_channel_layout_nb_channels( aohp->output_channel_layout );
+ aohp->output_block_align = (output_channels * aohp->output_bits_per_sample) / 8;
+ /* Set up resampler. */
+ AVAudioResampleContext *avr_ctx = aohp->avr_ctx;
+ avr_ctx = avresample_alloc_context();
+ if( !avr_ctx )
+ env->ThrowError( "%s: failed to avresample_alloc_context.", filter_name );
+ aohp->avr_ctx = avr_ctx;
+ av_opt_set_int( avr_ctx, "in_channel_layout", ctx->channel_layout, 0 );
+ av_opt_set_int( avr_ctx, "in_sample_fmt", ctx->sample_fmt, 0 );
+ av_opt_set_int( avr_ctx, "in_sample_rate", ctx->sample_rate, 0 );
+ av_opt_set_int( avr_ctx, "out_channel_layout", aohp->output_channel_layout, 0 );
+ av_opt_set_int( avr_ctx, "out_sample_fmt", aohp->output_sample_format, 0 );
+ av_opt_set_int( avr_ctx, "out_sample_rate", aohp->output_sample_rate, 0 );
+ av_opt_set_int( avr_ctx, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0 );
+ if( avresample_open( avr_ctx ) < 0 )
+ env->ThrowError( "%s: failed to open resampler.", filter_name );
+ /* Set up AviSynth output format. */
+ vi->nchannels = output_channels;
+ vi->audio_samples_per_second = aohp->output_sample_rate;
+ switch ( aohp->output_sample_format )
+ {
+ case AV_SAMPLE_FMT_U8 :
+ case AV_SAMPLE_FMT_U8P :
+ vi->sample_type = avxsynth::SAMPLE_INT8;
+ break;
+ case AV_SAMPLE_FMT_S16 :
+ case AV_SAMPLE_FMT_S16P :
+ vi->sample_type = avxsynth::SAMPLE_INT16;
+ break;
+ case AV_SAMPLE_FMT_S32 :
+ case AV_SAMPLE_FMT_S32P :
+ vi->sample_type = aohp->s24_output ? avxsynth::SAMPLE_INT24 : avxsynth::SAMPLE_INT32;
+ break;
+ case AV_SAMPLE_FMT_FLT :
+ case AV_SAMPLE_FMT_FLTP :
+ vi->sample_type = avxsynth::SAMPLE_FLOAT;
+ break;
+ default :
+ env->ThrowError( "%s: %s is not supported.", filter_name, av_get_sample_fmt_name( ctx->sample_fmt ) );
+ }
+}
diff --git a/AvxSynth/audio_output.h b/AvxSynth/audio_output.h
new file mode 100644
index 0000000..22c1318
--- /dev/null
+++ b/AvxSynth/audio_output.h
@@ -0,0 +1,35 @@
+/*****************************************************************************
+ * audio_output.h
+ *****************************************************************************
+ * Copyright (C) 2012-2013 L-SMASH Works project
+ *
+ * Authors: Yusuke Nakamura <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *****************************************************************************/
+
+/* This file is available under an ISC license.
+ * However, when distributing its binary file, it will be under LGPL or GPL. */
+
+#include "../common/audio_output.h"
+
+void as_setup_audio_rendering
+(
+ lw_audio_output_handler_t *aohp,
+ AVCodecContext *ctx,
+ avxsynth::VideoInfo *vi,
+ avxsynth::IScriptEnvironment *env,
+ const char *filter_name,
+ uint64_t channel_layout,
+ int sample_rate
+);
diff --git a/AvxSynth/avxplugin.h b/AvxSynth/avxplugin.h
new file mode 100644
index 0000000..fd32d5f
--- /dev/null
+++ b/AvxSynth/avxplugin.h
@@ -0,0 +1,763 @@
+// Avisynth v4.0 Copyright 2002 Ben Rudiak-Gould et al.
+// http://www.avisynth.org
+// http://www.avxsynth.org
+
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
+// http://www.gnu.org/copyleft/gpl.html .
+//
+// Linking Avisynth statically or dynamically with other modules is making a
+// combined work based on Avisynth. Thus, the terms and conditions of the GNU
+// General Public License cover the whole combination.
+//
+// As a special exception, the copyright holders of Avisynth give you
+// permission to link Avisynth with independent modules that communicate with
+// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
+// terms of these independent modules, and to copy and distribute the
+// resulting combined work under terms of your choice, provided that
+// every copy of the combined work is accompanied by a complete copy of
+// the source code of Avisynth (the version of Avisynth used to produce the
+// combined work), being distributed under the terms of the GNU General
+// Public License plus this exception. An independent module is a module
+// which is not derived from or based on Avisynth, such as 3rd-party filters,
+// import and export plugins, or graphical user interfaces.
+
+
+#define LINUXIZED_VERSION
+
+
+#ifndef __AVXPLUGIN_H__
+#define __AVXPLUGIN_H__
+
+/* Define all types necessary for interfacing with avisynth.dll
+ Moved from internal.h */
+#ifdef LINUXIZED_VERSION
+#include "windowsPorts/windows2linux.h"
+#else // LINUXIZED_VERSION
+// Win32 API macros, notably the types BYTE, DWORD, ULONG, etc.
+//#include <windef.h>
+
+// COM interface macros
+//#include <objbase.h>
+#endif // LINUXIZED_VERSION
+#include <stdio.h>
+
+namespace avxsynth {
+
+
+enum { AVISYNTH_INTERFACE_VERSION = 3 };
+
+// Raster types used by VirtualDub & Avisynth
+#define in64 (__int64)(unsigned short)
+typedef uint32_t Pixel;
+typedef uint32_t Pixel32;
+typedef unsigned char Pixel8;
+typedef long PixCoord;
+typedef long PixDim;
+typedef long PixOffset;
+
+
+/* Compiler-specific crap */
+
+// Tell MSVC to stop precompiling here
+#ifdef _MSC_VER
+ #pragma hdrstop
+#endif
+
+// Set up debugging macros for MS compilers; for others, step down to the
+// standard <assert.h> interface
+#ifdef _MSC_VER
+ #include <crtdbg.h>
+#else
+ #include <assert.h>
+ #define _ASSERT(x) assert(x)
+ #define _ASSERTE(x) assert(x)
+#endif
+
+
+
+// I had problems with Premiere wanting 1-byte alignment for its structures,
+// so I now set the Avisynth struct alignment explicitly here.
+#pragma pack(push,8)
+
+#define FRAME_ALIGN 16
+// Default frame alignment is 16 bytes, to help P4, when using SSE2
+
+// The VideoInfo struct holds global information about a clip (i.e.
+// information that does not depend on the frame number). The GetVideoInfo
+// method in IClip returns this struct.
+
+// Audio Sample information
+typedef float SFLOAT;
+
+enum {SAMPLE_INT8 = 1<<0,
+ SAMPLE_INT16 = 1<<1,
+ SAMPLE_INT24 = 1<<2, // Int24 is a very stupid thing to code, but it's supported by some hardware.
+ SAMPLE_INT32 = 1<<3,
+ SAMPLE_FLOAT = 1<<4};
+
+enum {
+ PLANAR_Y=1<<0,
+ PLANAR_U=1<<1,
+ PLANAR_V=1<<2,
+ PLANAR_ALIGNED=1<<3,
+ PLANAR_Y_ALIGNED=PLANAR_Y|PLANAR_ALIGNED,
+ PLANAR_U_ALIGNED=PLANAR_U|PLANAR_ALIGNED,
+ PLANAR_V_ALIGNED=PLANAR_V|PLANAR_ALIGNED,
+ };
+
+class AvisynthError /* exception */ {
+public:
+ const char* const msg;
+ AvisynthError(const char* _msg) : msg(_msg) {}
+};
+
+struct VideoInfo {
+ int width, height; // width=0 means no video
+ unsigned fps_numerator, fps_denominator;
+ int num_frames;
+ // This is more extensible than previous versions. More properties can be added seeminglesly.
+
+ // Colorspace properties.
+ enum {
+ CS_BGR = 1<<28,
+ CS_YUV = 1<<29,
+ CS_INTERLEAVED = 1<<30,
+ CS_PLANAR = 1<<31
+ };
+
+ // Specific colorformats
+ enum { CS_UNKNOWN = 0,
+ CS_BGR24 = 1<<0 | CS_BGR | CS_INTERLEAVED,
+ CS_BGR32 = 1<<1 | CS_BGR | CS_INTERLEAVED,
+ CS_YUY2 = 1<<2 | CS_YUV | CS_INTERLEAVED,
+ CS_YV12 = 1<<3 | CS_YUV | CS_PLANAR, // y-v-u, 4:2:0 planar
+ CS_I420 = 1<<4 | CS_YUV | CS_PLANAR, // y-u-v, 4:2:0 planar
+ CS_IYUV = 1<<4 | CS_YUV | CS_PLANAR, // same as above
+ };
+ int pixel_type; // changed to int as of 2.5
+
+
+ int audio_samples_per_second; // 0 means no audio
+ int sample_type; // as of 2.5
+ __int64 num_audio_samples; // changed as of 2.5
+ int nchannels; // as of 2.5
+
+ // Imagetype properties
+
+ int image_type;
+
+ enum {
+ IT_BFF = 1<<0,
+ IT_TFF = 1<<1,
+ IT_FIELDBASED = 1<<2
+ };
+
+ // useful functions of the above
+ bool HasVideo() const { return (width!=0); }
+ bool HasAudio() const { return (audio_samples_per_second!=0); }
+ bool IsRGB() const { return !!(pixel_type&CS_BGR); }
+ bool IsRGB24() const { return (pixel_type&CS_BGR24)==CS_BGR24; } // Clear out additional properties
+ bool IsRGB32() const { return (pixel_type & CS_BGR32) == CS_BGR32 ; }
+ bool IsYUV() const { return !!(pixel_type&CS_YUV ); }
+ bool IsYUY2() const { return (pixel_type & CS_YUY2) == CS_YUY2; }
+ bool IsYV12() const { return ((pixel_type & CS_YV12) == CS_YV12)||((pixel_type & CS_I420) == CS_I420); }
+ bool IsColorSpace(int c_space) const { return ((pixel_type & c_space) == c_space); }
+ bool Is(int property) const { return ((pixel_type & property)==property ); }
+ bool IsPlanar() const { return !!(pixel_type & CS_PLANAR); }
+ bool IsFieldBased() const { return !!(image_type & IT_FIELDBASED); }
+ bool IsParityKnown() const { return ((image_type & IT_FIELDBASED)&&(image_type & (IT_BFF|IT_TFF))); }
+ bool IsBFF() const { return !!(image_type & IT_BFF); }
+ bool IsTFF() const { return !!(image_type & IT_TFF); }
+
+ bool IsVPlaneFirst() const {return ((pixel_type & CS_YV12) == CS_YV12); } // Don't use this
+ int BytesFromPixels(int pixels) const { return pixels * (BitsPerPixel()>>3); } // Will not work on planar images, but will return only luma planes
+ int RowSize() const { return BytesFromPixels(width); } // Also only returns first plane on planar images
+ int BMPSize() const { if (IsPlanar()) {int p = height * ((RowSize()+3) & ~3); p+=p>>1; return p; } return height * ((RowSize()+3) & ~3); }
+ __int64 AudioSamplesFromFrames(__int64 frames) const { return (fps_numerator && HasVideo()) ? ((__int64)(frames) * audio_samples_per_second * fps_denominator / fps_numerator) : 0; }
+ int FramesFromAudioSamples(__int64 samples) const { return (fps_denominator && HasAudio()) ? (int)((samples * (__int64)fps_numerator)/((__int64)fps_denominator * (__int64)audio_samples_per_second)) : 0; }
+ __int64 AudioSamplesFromBytes(__int64 bytes) const { return HasAudio() ? bytes / BytesPerAudioSample() : 0; }
+ __int64 BytesFromAudioSamples(__int64 samples) const { return samples * BytesPerAudioSample(); }
+ int AudioChannels() const { return HasAudio() ? nchannels : 0; }
+ int SampleType() const{ return sample_type;}
+ bool IsSampleType(int testtype) const{ return !!(sample_type&testtype);}
+ int SamplesPerSecond() const { return audio_samples_per_second; }
+ int BytesPerAudioSample() const { return nchannels*BytesPerChannelSample();}
+ void SetFieldBased(bool isfieldbased) { if (isfieldbased) image_type|=IT_FIELDBASED; else image_type&=~IT_FIELDBASED; }
+ void Set(int property) { image_type|=property; }
+ void Clear(int property) { image_type&=~property; }
+
+ int BitsPerPixel() const {
+ switch (pixel_type) {
+ case CS_BGR24:
+ return 24;
+ case CS_BGR32:
+ return 32;
+ case CS_YUY2:
+ return 16;
+ case CS_YV12:
+ case CS_I420:
+ return 12;
+ default:
+ return 0;
+ }
+ }
+
+ int BytesPerChannelSample() const {
+ switch (sample_type) {
+ case SAMPLE_INT8:
+ return sizeof(signed char);
+ case SAMPLE_INT16:
+ return sizeof(signed short);
+ case SAMPLE_INT24:
+ return 3;
+ case SAMPLE_INT32:
+ return sizeof(signed int);
+ case SAMPLE_FLOAT:
+ return sizeof(SFLOAT);
+ default:
+ _ASSERTE("Sample type not recognized!");
+ return 0;
+ }
+ }
+
+ // useful mutator
+ void SetFPS(unsigned numerator, unsigned denominator) {
+ if ((numerator == 0) || (denominator == 0)) {
+ fps_numerator = 0;
+ fps_denominator = 1;
+ }
+ else {
+ unsigned x=numerator, y=denominator;
+ while (y) { // find gcd
+ unsigned t = x%y; x = y; y = t;
+ }
+ fps_numerator = numerator/x;
+ fps_denominator = denominator/x;
+ }
+ }
+
+ // Range protected multiply-divide of FPS
+ void MulDivFPS(unsigned multiplier, unsigned divisor) {
+ uint64_t numerator = UInt32x32To64(fps_numerator, multiplier);
+ uint64_t denominator = UInt32x32To64(fps_denominator, divisor);
+
+ uint64_t x=numerator, y=denominator;
+ while (y) { // find gcd
+ uint64_t t = x%y; x = y; y = t;
+ }
+ numerator /= x; // normalize
+ denominator /= x;
+
+ uint64_t temp = numerator | denominator; // Just looking top bit
+ unsigned u = 0;
+ while (temp & 0xffffffff80000000) { // or perhaps > 16777216*2
+ temp = Int64ShrlMod32(temp, 1);
+ u++;
+ }
+ if (u) { // Scale to fit
+ const unsigned round = 1 << (u-1);
+ SetFPS( (unsigned)Int64ShrlMod32(numerator + round, u),
+ (unsigned)Int64ShrlMod32(denominator + round, u) );
+ }
+ else {
+ fps_numerator = (unsigned)numerator;
+ fps_denominator = (unsigned)denominator;
+ }
+ }
+
+ // Test for same colorspace
+ bool IsSameColorspace(const VideoInfo& vi) const {
+ if (vi.pixel_type == pixel_type) return TRUE;
+ if (IsYV12() && vi.IsYV12()) return TRUE;
+ return FALSE;
+ }
+};
+
+
+
+
+// VideoFrameBuffer holds information about a memory block which is used
+// for video data. For efficiency, instances of this class are not deleted
+// when the refcount reaches zero; instead they're stored in a linked list
+// to be reused. The instances are deleted when the corresponding AVS
+// file is closed.
+
+class VideoFrameBuffer {
+ BYTE* const data;
+ const int data_size;
+ // sequence_number is incremented every time the buffer is changed, so
+ // that stale views can tell they're no longer valid.
+ long sequence_number;
+
+ friend class VideoFrame;
+ friend class Cache;
+ friend class ScriptEnvironment;
+ long refcount;
+
+public:
+ VideoFrameBuffer(int size);
+ VideoFrameBuffer();
+ ~VideoFrameBuffer();
+
+ const BYTE* GetReadPtr() const { return data; }
+ BYTE* GetWritePtr() { ++sequence_number; return data; }
+ int GetDataSize() { return data_size; }
+ int GetSequenceNumber() { return sequence_number; }
+ int GetRefcount() { return refcount; }
+};
+
+
+class IClip;
+class PClip;
+class PVideoFrame;
+class IScriptEnvironment;
+class AVSValue;
+
+
+// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new
+// is overloaded to recycle class instances.
+
+class VideoFrame {
+ int refcount;
+ VideoFrameBuffer* const vfb;
+ const int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture.
+
+ friend class PVideoFrame;
+ void AddRef() { InterlockedIncrement((long *)&refcount); }
+ void Release() { if (refcount==1) InterlockedDecrement(&vfb->refcount); InterlockedDecrement((long *)&refcount); }
+
+ friend class ScriptEnvironment;
+ friend class Cache;
+
+ VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height);
+ VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV);
+
+#ifdef LINUXIZED_VERSION
+ void* operator new(size_t size);
+#else
+// void* operator new(unsigned size);
+#endif // LINUXIZED_VERSION
+
+// TESTME: OFFSET U/V may be switched to what could be expected from AVI standard!
+public:
+ int GetPitch() const { return pitch; }
+ int GetPitch(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: return pitchUV;} return pitch; }
+ int GetRowSize() const { return row_size; }
+ int GetRowSize(int plane) const {
+ switch (plane) {
+ case PLANAR_U: case PLANAR_V: if (pitchUV) return row_size>>1; else return 0;
+ case PLANAR_U_ALIGNED: case PLANAR_V_ALIGNED:
+ if (pitchUV) {
+ int r = ((row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)) )>>1; // Aligned rowsize
+ if (r<=pitchUV)
+ return r;
+ return row_size>>1;
+ } else return 0;
+ case PLANAR_Y_ALIGNED:
+ int r = (row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)); // Aligned rowsize
+ if (r<=pitch)
+ return r;
+ return row_size;
+ }
+ return row_size; }
+ int GetHeight() const { return height; }
+ int GetHeight(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: if (pitchUV) return height>>1; return 0;} return height; }
+
+ // generally you shouldn't use these three
+ VideoFrameBuffer* GetFrameBuffer() const { return vfb; }
+ int GetOffset() const { return offset; }
+ int GetOffset(int plane) const { switch (plane) {case PLANAR_U: return offsetU;case PLANAR_V: return offsetV;default: return offset;}; }
+
+ // in plugins use env->SubFrame()
+ VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const;
+ VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV) const;
+
+
+ const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; }
+ const BYTE* GetReadPtr(int plane) const { return vfb->GetReadPtr() + GetOffset(plane); }
+
+ bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); }
+
+ BYTE* GetWritePtr() const {
+ if (vfb->GetRefcount()>1) {
+ _ASSERT(FALSE);
+ //throw AvisynthError("Internal Error - refcount was more than one!");
+ }
+ return IsWritable() ? (vfb->GetWritePtr() + offset) : 0;
+ }
+
+ BYTE* GetWritePtr(int plane) const {
+ if (plane==PLANAR_Y) {
+ if (vfb->GetRefcount()>1) {
+ _ASSERT(FALSE);
+// throw AvisynthError("Internal Error - refcount was more than one!");
+ }
+ return IsWritable() ? vfb->GetWritePtr() + GetOffset(plane) : 0;
+ }
+ return vfb->data + GetOffset(plane);
+ }
+
+ ~VideoFrame() { InterlockedDecrement(&vfb->refcount); }
+};
+
+enum {
+ CACHE_NOTHING=0,
+ CACHE_RANGE=1,
+ CACHE_ALL=2,
+ CACHE_AUDIO=3,
+ CACHE_AUDIO_NONE=4,
+ CACHE_AUDIO_AUTO=5
+ };
+
+// Base class for all filters.
+class IClip {
+ friend class PClip;
+ friend class AVSValue;
+ int refcnt;
+ void AddRef() { InterlockedIncrement((long *)&refcnt); }
+ void Release() { InterlockedDecrement((long *)&refcnt); if (!refcnt) delete this; }
+public:
+ IClip() : refcnt(0) {}
+
+ virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; }
+
+ virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0;
+ virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame
+ virtual void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) = 0; // start and count are in samples
+ virtual void __stdcall SetCacheHints(int cachehints,size_t frame_range) = 0 ; // We do not pass cache requests upwards, only to the next filter.
+ virtual const VideoInfo& __stdcall GetVideoInfo() = 0;
+ virtual __stdcall ~IClip() {}
+};
+
+
+// smart pointer to IClip
+class PClip {
+
+ IClip* p;
+
+ IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; }
+ friend class AVSValue;
+ friend class VideoFrame;
+
+ void Init(IClip* x) {
+ if (x) x->AddRef();
+ p=x;
+ }
+ void Set(IClip* x) {
+ if (x) x->AddRef();
+ if (p) p->Release();
+ p=x;
+ }
+
+public:
+ PClip() { p = 0; }
+ PClip(const PClip& x) { Init(x.p); }
+ PClip(IClip* x) { Init(x); }
+ void operator=(IClip* x) { Set(x); }
+ void operator=(const PClip& x) { Set(x.p); }
+
+ bool operator==(const PClip& cmp) { return this->p == cmp.p;}
+
+ IClip* operator->() const { return p; }
+
+ // useful in conditional expressions
+ operator void*() const { return p; }
+ bool operator!() const { return !p; }
+
+ ~PClip() { if (p) p->Release(); }
+};
+
+
+// smart pointer to VideoFrame
+class PVideoFrame {
+
+ VideoFrame* p;
+
+ void Init(VideoFrame* x) {
+ if (x) x->AddRef();
+ p=x;
+ }
+ void Set(VideoFrame* x) {
+ if (x) x->AddRef();
+ if (p) p->Release();
+ p=x;
+ }
+
+public:
+ PVideoFrame() { p = 0; }
+ PVideoFrame(const PVideoFrame& x) { Init(x.p); }
+ PVideoFrame(VideoFrame* x) { Init(x); }
+ void operator=(VideoFrame* x) { Set(x); }
+ void operator=(const PVideoFrame& x) { Set(x.p); }
+
+ VideoFrame* operator->() const { return p; }
+
+ // for conditional expressions
+ operator void*() const { return p; }
+ bool operator!() const { return !p; }
+
+ ~PVideoFrame() { if (p) p->Release();}
+};
+
+
+class AVSValue {
+public:
+
+ AVSValue() { type = 'v'; }
+ AVSValue(IClip* c) { type = 'c'; u.clip = c; if (c) c->AddRef(); }
+ AVSValue(const PClip& c) { type = 'c'; u.clip = c.GetPointerWithAddRef(); }
+ AVSValue(bool b) { type = 'b'; u.boolean = b; }
+ AVSValue(int i) { type = 'i'; u.integer = i; }
+ AVSValue(__int64 l) { type = 'l'; u.int64Val = l; }
+ AVSValue(float f) { type = 'f'; u.floating_pt = f; }
+ AVSValue(double f) { type = 'f'; u.floating_pt = float(f); }
+ AVSValue(const char* s) { type = 's'; u.string = s; }
+ AVSValue(const AVSValue* a, int size) { type = 'a'; u.array = a; array_size = size; }
+ AVSValue(const AVSValue& v) { Assign(&v, true); }
+
+ ~AVSValue() { if (IsClip() && u.clip) u.clip->Release(); }
+ AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; }
+
+ // Note that we transparently allow 'int' to be treated as 'float'.
+ // There are no int<->bool conversions, though.
+
+ bool Defined() const { return type != 'v'; }
+ bool IsClip() const { return type == 'c'; }
+ bool IsBool() const { return type == 'b'; }
+ bool IsInt() const { return type == 'i'; }
+ bool IsInt64() const { return (type == 'l'|| type == 'i'); }
+ bool IsFloat() const { return type == 'f' || type == 'i'; }
+ bool IsString() const { return type == 's'; }
+ bool IsArray() const { return type == 'a'; }
+
+ PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?u.clip:0; }
+ bool AsBool() const { _ASSERTE(IsBool()); return u.boolean; }
+ int AsInt() const { _ASSERTE(IsInt()); return u.integer; }
+ __int64 AsLong() const { _ASSERTE(IsInt64()); return u.int64Val; }
+ const char* AsString() const { _ASSERTE(IsString()); return IsString()?u.string:0; }
+ double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?u.integer:u.floating_pt; }
+
+ bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? u.boolean : def; }
+ int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? u.integer : def; }
+ double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? u.integer : type=='f' ? u.floating_pt : def; }
+ const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? u.string : def; }
+
+ int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; }
+
+ const AVSValue& operator[](int index) const {
+ _ASSERTE(IsArray() && index>=0 && index<array_size);
+ return (IsArray() && index>=0 && index<array_size) ? u.array[index] : *this;
+ }
+
+private:
+
+ short type; // 'a'rray, 'c'lip, 'b'ool, 'i'nt, 'f'loat, 's'tring, 'v'oid, or 'l'onglong
+ short array_size;
+ union {
+ IClip* clip;
+ bool boolean;
+ int integer;
+ __int64 int64Val;
+ float floating_pt;
+ const char* string;
+ const AVSValue* array;
+// __int64 longlong;
+ } u;
+
+ void Assign(const AVSValue* src, bool init) {
+ if (src->IsClip() && src->u.clip)
+ src->u.clip->AddRef();
+ if (!init && IsClip() && u.clip)
+ u.clip->Release();
+ this->type = src->type;
+ this->array_size = src->array_size;
+ this->u = src->u; // in case of string, hard-copying seems to be counted on to work
+ }
+};
+
+
+// instantiable null filter
+class GenericVideoFilter : public IClip {
+protected:
+ PClip child;
+ VideoInfo vi;
+public:
+ GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); }
+ PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); }
+ void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); }
+ const VideoInfo& __stdcall GetVideoInfo() { return vi; }
+ bool __stdcall GetParity(int n) { return child->GetParity(n); }
+ void __stdcall SetCacheHints(int cachehints,size_t frame_range) { } ; // We do not pass cache requests upwards, only to the next filter.
+};
+
+
+
+
+
+/* Helper classes useful to plugin authors */
+
+class AlignPlanar : public GenericVideoFilter
+{
+public:
+ AlignPlanar(PClip _clip);
+ static PClip Create(PClip clip);
+ PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
+};
+
+
+
+class FillBorder : public GenericVideoFilter
+{
+public:
+ FillBorder(PClip _clip);
+ static PClip Create(PClip clip);
+ PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
+};
+
+
+
+class ConvertAudio : public GenericVideoFilter
+/**
+ * Helper class to convert audio to any format
+ **/
+{
+public:
+ ConvertAudio(PClip _clip, int prefered_format);
+ void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env);
+ void __stdcall SetCacheHints(int cachehints,size_t frame_range); // We do pass cache requests upwards, to the cache!
+
+ static PClip Create(PClip clip, int sample_type, int prefered_type);
+ static AVSValue __cdecl Create_float(AVSValue args, void*, IScriptEnvironment*);
+ static AVSValue __cdecl Create_32bit(AVSValue args, void*, IScriptEnvironment*);
+ static AVSValue __cdecl Create_24bit(AVSValue args, void*, IScriptEnvironment*);
+ static AVSValue __cdecl Create_16bit(AVSValue args, void*, IScriptEnvironment*);
+ static AVSValue __cdecl Create_8bit (AVSValue args, void*, IScriptEnvironment*);
+ static AVSValue __cdecl Create_Any (AVSValue args, void*, IScriptEnvironment*);
+ virtual ~ConvertAudio();
+
+private:
+ void convertToFloat(char* inbuf, float* outbuf, char sample_type, int count);
+ void convertToFloat_3DN(char* inbuf, float* outbuf, char sample_type, int count);
+ void convertToFloat_SSE(char* inbuf, float* outbuf, char sample_type, int count);
+ void convertToFloat_SSE2(char* inbuf, float* outbuf, char sample_type, int count);
+ void convertFromFloat(float* inbuf, void* outbuf, char sample_type, int count);
+ void convertFromFloat_3DN(float* inbuf, void* outbuf, char sample_type, int count);
+ void convertFromFloat_SSE(float* inbuf, void* outbuf, char sample_type, int count);
+ void convertFromFloat_SSE2(float* inbuf, void* outbuf, char sample_type, int count);
+
+ __inline int Saturate_int8(float n);
+ __inline short Saturate_int16(float n);
+ __inline int Saturate_int24(float n);
+ __inline int Saturate_int32(float n);
+
+ char src_format;
+ char dst_format;
+ int src_bps;
+ char *tempbuffer;
+ SFLOAT *floatbuffer;
+ int tempbuffer_size;
+};
+
+
+// For GetCPUFlags. These are backwards-compatible with those in VirtualDub.
+enum {
+ /* slowest CPU to support extension */
+ CPUF_FORCE = 0x01, // N/A
+ CPUF_FPU = 0x02, // 386/486DX
+ CPUF_MMX = 0x04, // P55C, K6, PII
+ CPUF_INTEGER_SSE = 0x08, // PIII, Athlon
+ CPUF_SSE = 0x10, // PIII, Athlon XP/MP
+ CPUF_SSE2 = 0x20, // PIV, Hammer
+ CPUF_3DNOW = 0x40, // K6-2
+ CPUF_3DNOW_EXT = 0x80, // Athlon
+ CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which
+ // only Hammer will have anyway)
+ CPUF_SSE3 = 0x100, // PIV+, Hammer
+};
+#define MAX_INT 0x7fffffff
+#define MIN_INT -0x7fffffff // ::FIXME:: research why this is not 0x80000000
+
+
+
+class IScriptEnvironment {
+public:
+ virtual __stdcall ~IScriptEnvironment() {}
+
+ virtual /*static*/ long __stdcall GetCPUFlags() = 0;
+
+ virtual char* __stdcall SaveString(const char* s, int length = -1) = 0;
+ virtual char* __stdcall Sprintf(const char* fmt, ...) = 0;
+ // note: val is really a va_list; I hope everyone typedefs va_list to a pointer
+ virtual char* __stdcall VSprintf(const char* fmt, va_list val) = 0;
+
+ __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0;
+
+ class NotFound /*exception*/ {}; // thrown by Invoke and GetVar
+
+ typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env);
+
+ virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0;
+ virtual void __stdcall AddBuiltInFunction(unsigned int nFunctionFamilyIndex, const char* name, const char* params, ApplyFunc apply, void* user_data) = 0;
+ virtual bool __stdcall FunctionExists(const char* name) = 0;
+ virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0;
+
+ virtual AVSValue __stdcall GetVar(const char* name) = 0;
+ virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0;
+ virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0;
+
+ virtual void __stdcall PushContext(int level=0) = 0;
+ virtual void __stdcall PopContext() = 0;
+
+ // align should be 4 or 8
+ virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=FRAME_ALIGN) = 0;
+
+ virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0;
+
+ virtual /*static*/ void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0;
+
+ typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env);
+ virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0;
+
+ virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0;
+
+ virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0;
+
+ virtual int __stdcall SetMemoryMax(int mem) = 0;
+
+ virtual int __stdcall SetWorkingDir(const char * newdir) = 0;
+
+ virtual void* __stdcall ManageCache(int key, void* data) = 0;
+
+ enum PlanarChromaAlignmentMode {
+ PlanarChromaAlignmentOff,
+ PlanarChromaAlignmentOn,
+ PlanarChromaAlignmentTest };
+
+ virtual bool __stdcall PlanarChromaAlignment(PlanarChromaAlignmentMode key) = 0;
+
+ virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0;
+};
+
+
+// avisynth.dll exports this; it's a way to use it as a library, without
+// writing an AVS script or without going through AVIFile.
+extern "C" IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION);
+
+#pragma pack(pop)
+
+}; // namespace avxsynth
+
+#endif //__AVXPLUGIN_H__
diff --git a/AvxSynth/configure b/AvxSynth/configure
new file mode 100755
index 0000000..570438d
--- /dev/null
+++ b/AvxSynth/configure
@@ -0,0 +1,314 @@
+#!/bin/bash
+
+#----------------------------------------------------------------------------------------------
+# configure script for AvxSynth plugins
+#----------------------------------------------------------------------------------------------
+
+# -- help -------------------------------------------------------------------------------------
+if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
+cat << EOF
+Usage: [PKG_CONFIG_PATH=/foo/bar/lib/pkgconfig] ./configure [options]
+options:
+ -h, --help print help (this)
+
+ --prefix=PREFIX install architecture-independent files into
+ PREFIX [/usr/local]
+ --exec-prefix=EPREFIX install architecture-dependent files into
+ EPREFIX [PREFIX]
+ --libdir=DIR install libs in DIR [EPREFIX/lib]
+
+ --extra-cppflags=XCPPFLAGS add XCPPFLAGS to CPPFLAGS
+ --extra-cflags=XCFLAGS add XCFLAGS to CFLAGS
+ --extra-cxxflags=XCXXFLAGS add XCXXFLAGS to CXXFLAGS
+ --extra-ldflags=XLDFLAGS add XLDFLAGS to LDFLAGS
+ --extra-libs=XLIBS add XLIBS to LIBS
+
+ --target-os=TARGET_OS select target operating system
+ --cross-prefix=PREFIX use PREFIX for compilation tools
+ --sysroot=SYSROOT root of cross-build tree
+
+EOF
+exit 1
+fi
+
+#-- func --------------------------------------------------------------------------------------
+error_exit()
+{
+ echo error: $1
+ exit 1
+}
+
+log_echo()
+{
+ echo $1
+ echo >> config.log
+ echo --------------------------------- >> config.log
+ echo $1 >> config.log
+}
+
+cc_check()
+{
+ rm -f conftest.c
+ if [ -n "$3" ]; then
+ echo "#include <$3>" >> config.log
+ echo "#include <$3>" > conftest.c
+ fi
+ echo "int main(void){$4 return 0;}" >> config.log
+ echo "int main(void){$4 return 0;}" >> conftest.c
+ echo $CC conftest.c -o conftest $1 $2 >> config.log
+ $CC conftest.c -o conftest $1 $2 2>> config.log
+ ret=$?
+ echo $ret >> config.log
+ rm -f conftest*
+ return $ret
+}
+#----------------------------------------------------------------------------------------------
+rm -f config.* .depend
+
+SRCDIR="$(cd $(dirname $0); pwd)"
+test "$SRCDIR" = "$(pwd)" && SRCDIR=.
+test -n "$(echo $SRCDIR | grep ' ')" && \
+ error_exit "out-of-tree builds are impossible with whitespace in source path"
+
+# -- output config.h --------------------------------------------------------------------------
+pushd $SRCDIR
+REV="$(git rev-list HEAD 2> /dev/null | wc -l | sed 's/ //g')"
+HASH="$(git describe --always 2> /dev/null)"
+popd
+cat >> config.h << EOF
+#define LSMASHWORKS_REV "$REV"
+#define LSMASHWORKS_GIT_HASH "$HASH"
+EOF
+
+# -- init -------------------------------------------------------------------------------------
+CC="gcc"
+CXX="g++"
+LD="g++"
+RANLIB="ranlib"
+AR="ar"
+STRIP="strip"
+
+prefix=""
+exec_prefix=""
+libdir=""
+DESTDIR=""
+
+CPPFLAGS="-D__STDC_CONSTANT_MACROS -D_FILE_OFFSET_BITS=64"
+CFLAGS="-Wall -std=gnu99 -I. -I$SRCDIR"
+CXXFLAGS="-Wall -I. -I$SRCDIR"
+LDFLAGS="-L."
+DEPLIBS="liblsmash libavformat libavcodec libswscale libavutil"
+
+# -- options ----------------------------------------------------------------------------------
+echo all command lines: > config.log
+echo "$*" >> config.log
+
+for opt; do
+ optarg="${opt#*=}"
+ case "$opt" in
+ --prefix=*)
+ prefix="$optarg"
+ ;;
+ --exec-prefix=*)
+ exec_prefix="$optarg"
+ ;;
+ --libdir=*)
+ libdir="$optarg"
+ ;;
+ --destdir=*)
+ DESTDIR="$optarg"
+ ;;
+ --extra-cppflags=*)
+ XCPPFLAGS="$optarg"
+ ;;
+ --extra-cflags=*)
+ XCFLAGS="$optarg"
+ ;;
+ --extra-cxxflags=*)
+ XCXXFLAGS="$optarg"
+ ;;
+ --extra-ldflags=*)
+ XLDFLAGS="$optarg"
+ ;;
+ --extra-libs=*)
+ XLIBS="$optarg"
+ ;;
+ --target-os=*)
+ TARGET_OS="$optarg"
+ ;;
+ --cross-prefix=*)
+ CROSS="$optarg"
+ ;;
+ --sysroot=*)
+ CFLAGS="$CFLAGS --sysroot=$optarg"
+ LDFLAGS="$LDFLAGS --sysroot=$optarg"
+ ;;
+ *)
+ error_exit "unknown option $opt"
+ ;;
+ esac
+done
+
+test -n "$prefix" || prefix="/usr/local"
+test -n "$exec_prefix" || exec_prefix='${prefix}'
+test -n "$libdir" || libdir='${exec_prefix}/lib'
+
+BASENAME="libavxlsmashsource"
+
+if test -n "$TARGET_OS"; then
+ TARGET_OS=$(echo $TARGET_OS | tr '[A-Z]' '[a-z]')
+else
+ TARGET_OS=$($CC -dumpmachine | tr '[A-Z]' '[a-z]')
+fi
+case "$TARGET_OS" in
+ *darwin*)
+ SYS="MACOSX"
+ SOSUFFIX="dylib"
+ SONAME="$BASENAME.$REV.$SOSUFFIX"
+ SONAME_LN="$BASENAME.$SOSUFFIX"
+ SOFLAGS="-dynamiclib -Wl,-single_module -Wl,-read_only_relocs,suppress -install_name $(DESTDIR)$(libdir)/$(SONAME)"
+ ;;
+ *)
+ SOSUFFIX="so"
+ SONAME="$BASENAME.$SOSUFFIX.$REV"
+ SONAME_LN="$BASENAME.$SOSUFFIX"
+ SOFLAGS="-Wl,-soname,$SONAME"
+ ;;
+esac
+
+# -- add extra --------------------------------------------------------------------------------
+if test -n "$prefix"; then
+ CFLAGS="$CFLAGS -I$prefix/include"
+ LDFLAGS="$LDFLAGS -L$prefix/lib"
+fi
+test -n "$libdir" && LDFLAGS="$LDFLAGS -L$libdir"
+
+CPPFLAGS="$CPPFLAGS $XCPPFLAGS"
+CFLAGS="$CFLAGS $XCFLAGS"
+CXXFLAGS="$CXXFLAGS $XCXXFLAGS"
+LDFLAGS="$LDFLAGS $XLDFLAGS"
+
+# -- check_exe --------------------------------------------------------------------------------
+CC="${CROSS}${CC}"
+CXX="${CROSS}${CXX}"
+LD="${CROSS}${LD}"
+STRIP="${CROSS}${STRIP}"
+for f in "$CC" "$LD" "$STRIP"; do
+ test -n "$(which $f 2> /dev/null)" || error_exit "$f is not executable"
+done
+
+# -- check & set cflags and ldflags ----------------------------------------------------------
+log_echo "CFLAGS/LDFLAGS checking..."
+if ! cc_check "$CFLAGS" "$LDFLAGS"; then
+ error_exit "invalid CFLAGS/LDFLAGS"
+fi
+if cc_check "-Os -ffast-math $CFLAGS" "$LDFLAGS"; then
+ CFLAGS="-Os -ffast-math $CFLAGS"
+fi
+if cc_check "$CFLAGS -fexcess-precision=fast" "$LDFLAGS"; then
+ CFLAGS="$CFLAGS -fexcess-precision=fast"
+fi
+
+# -- check pkg-config ----------------------------------------------------------------
+PKGCONFIGEXE="pkg-config"
+test -n "$(which ${CROSS}${PKGCONFIGEXE} 2> /dev/null)" && \
+ PKGCONFIGEXE=${CROSS}${PKGCONFIGEXE}
+
+if $PKGCONFIGEXE --exists $DEPLIBS 2> /dev/null; then
+ LIBS="$($PKGCONFIGEXE --libs $DEPLIBS)"
+ CFLAGS="$CFLAGS $($PKGCONFIGEXE --cflags $DEPLIBS)"
+else
+ for lib in $DEPLIBS; do
+ LIBS="$LIBS -l${lib#lib}"
+ done
+ log_echo "warning: pkg-config or pc files not found, lib detection may be inaccurate."
+fi
+
+# -- check lsmash -----------------------------------------------------------------------------
+log_echo "checking for liblsmash..."
+if ! cc_check "$CFLAGS" "$LDFLAGS $LIBS $XLIBS" "lsmash.h" "lsmash_open_movie(0,0);" ; then
+ log_echo "error: liblsmash checking failed"
+ error_exit "lsmash.h might not be installed or some libs missing."
+fi
+
+# -- check libav ------------------------------------------------------------------------------
+log_echo "checking for libavformat..."
+if ! cc_check "$CFLAGS" "$LDFLAGS $LIBS $XLIBS" "libavformat/avformat.h" "avformat_find_stream_info(0,0);" ; then
+ log_echo "error: libavformat checking failed."
+ error_exit "libavformat/avformat.h might not be installed or some libs missing."
+fi
+
+log_echo "checking for libavcodec..."
+if ! cc_check "$CFLAGS" "$LDFLAGS $LIBS $XLIBS" "libavcodec/avcodec.h" "avcodec_find_decoder(0);" ; then
+ log_echo "error: libavcodec checking failed."
+ error_exit "libavcodec/avcodec.h might not be installed or some libs missing."
+fi
+
+log_echo "checking for libswscale..."
+if ! cc_check "$CFLAGS" "$LDFLAGS $LIBS $XLIBS" "libswscale/swscale.h" "sws_getCachedContext(0,0,0,0,0,0,0,0,0,0,0);" ; then
+ log_echo "error: libswscale checking failed."
+ error_exit "libswscale/swscale.h might not be installed or some libs missing."
+fi
+
+# -- LDFLAGS settings --------------------------------------------------------------------------
+LDFLAGS="$LDFLAGS -shared"
+LIBS="$LIBS $XLIBS"
+
+# -- output config.mak ------------------------------------------------------------------------
+rm -f config.mak
+cat >> config.mak << EOF
+CC = $CC
+CXX = $CXX
+LD = $LD
+STRIP = $STRIP
+CPPFLAGS = $CPPFLAGS
+CFLAGS = $CFLAGS
+CXXFLAGS = $CXXFLAGS
+LDFLAGS = $LDFLAGS
+LIBS = $LIBS
+SRCDIR = $SRCDIR
+DESTDIR = $DESTDIR
+prefix = $prefix
+exec_prefix = $exec_prefix
+libdir = $libdir
+SRC_SOURCE = $SRC_SOURCE
+BASENAME=$BASENAME
+SONAME=$SONAME
+SONAME_LN=$SONAME_LN
+SOSUFFIX=$SOSUFFIX
+SOFLAGS=$SOFLAGS
+EOF
+
+cat >> config.log << EOF
+---------------------------------
+ setting
+---------------------------------
+EOF
+cat config.mak >> config.log
+
+cat << EOF
+
+settings...
+CC = $CC
+CXX = $CXX
+LD = $LD
+STRIP = $STRIP
+CPPFLAGS = $CPPFLAGS
+CFLAGS = $CFLAGS
+CXXFLAGS = $CXXFLAGS
+LDFLAGS = $LDFLAGS
+LIBS = $LIBS
+SONAME = $SONAME
+SOFLAGS = $SOFLAGS
+PREFIX = $prefix
+EOF
+
+test "$SRCDIR" = "." || cp -f $SRCDIR/GNUmakefile .
+
+# ---------------------------------------------------------------------------------------------
+
+cat << EOF
+
+configure finished.
+type 'make' : compile $SONAME
+EOF
diff --git a/AvxSynth/libavsmash_source.cpp b/AvxSynth/libavsmash_source.cpp
new file mode 100644
index 0000000..4246de7
--- /dev/null
+++ b/AvxSynth/libavsmash_source.cpp
@@ -0,0 +1,538 @@
+/*****************************************************************************
+ * libavsmash_source.cpp
+ *****************************************************************************
+ * Copyright (C) 2012-2013 L-SMASH Works project
+ *
+ * Authors: Yusuke Nakamura <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *****************************************************************************/
+
+/* This file is available under an ISC license.
+ * However, when distributing its binary file, it will be under LGPL or GPL. */
+
+#include "lsmashsource.h"
+
+extern "C"
+{
+/* L-SMASH */
+#define LSMASH_DEMUXER_ENABLED
+#include <lsmash.h> /* Demuxer */
+
+/* Libav
+ * The binary file will be LGPLed or GPLed. */
+#include <libavformat/avformat.h> /* Codec specific info importer */
+#include <libavcodec/avcodec.h> /* Decoder */
+#include <libswscale/swscale.h> /* Colorspace converter */
+#include <libavresample/avresample.h> /* Audio resampler */
+#include <libavutil/imgutils.h>
+#include <libavutil/mem.h>
+#include <libavutil/opt.h>
+}
+
+#include "video_output.h"
+#include "audio_output.h"
+#include "libavsmash_source.h"
+
+LSMASHVideoSource::LSMASHVideoSource
+(
+ const char *source,
+ uint32_t track_number,
+ int threads,
+ int seek_mode,
+ uint32_t forward_seek_threshold,
+ int direct_rendering,
+ int stacked_format,
+ enum AVPixelFormat pixel_format,
+ avxsynth::IScriptEnvironment *env
+)
+{
+ memset( &vi, 0, sizeof(avxsynth::VideoInfo) );
+ memset( &vdh, 0, sizeof(libavsmash_video_decode_handler_t) );
+ memset( &voh, 0, sizeof(libavsmash_video_output_handler_t) );
+ format_ctx = NULL;
+ vdh.seek_mode = seek_mode;
+ vdh.forward_seek_threshold = forward_seek_threshold;
+ as_video_output_handler_t *as_vohp = (as_video_output_handler_t *)lw_malloc_zero( sizeof(as_video_output_handler_t) );
+ if( !as_vohp )
+ env->ThrowError( "LSMASHVideoSource: failed to allocate the AviSynth video output handler." );
+ as_vohp->vi = &vi;
+ as_vohp->env = env;
+ voh.private_handler = as_vohp;
+ voh.free_private_handler = as_free_video_output_handler;
+ get_video_track( source, track_number, threads, env );
+ lsmash_discard_boxes( vdh.root );
+ prepare_video_decoding( direct_rendering, stacked_format, pixel_format, env );
+}
+
+LSMASHVideoSource::~LSMASHVideoSource()
+{
+ libavsmash_cleanup_video_decode_handler( &vdh );
+ libavsmash_cleanup_video_output_handler( &voh );
+ if( format_ctx )
+ avformat_close_input( &format_ctx );
+ lsmash_destroy_root( vdh.root );
+}
+
+uint32_t LSMASHVideoSource::open_file( const char *source, avxsynth::IScriptEnvironment *env )
+{
+ /* L-SMASH */
+ vdh.root = lsmash_open_movie( source, LSMASH_FILE_MODE_READ );
+ if( !vdh.root )
+ env->ThrowError( "LSMASHVideoSource: failed to lsmash_open_movie." );
+ lsmash_movie_parameters_t movie_param;
+ lsmash_initialize_movie_parameters( &movie_param );
+ lsmash_get_movie_parameters( vdh.root, &movie_param );
+ if( movie_param.number_of_tracks == 0 )
+ env->ThrowError( "LSMASHVideoSource: the number of tracks equals 0." );
+ /* libavformat */
+ av_register_all();
+ avcodec_register_all();
+ if( avformat_open_input( &format_ctx, source, NULL, NULL ) )
+ env->ThrowError( "LSMASHVideoSource: failed to avformat_open_input." );
+ if( avformat_find_stream_info( format_ctx, NULL ) < 0 )
+ env->ThrowError( "LSMASHVideoSource: failed to avformat_find_stream_info." );
+ /* */
+ lw_log_handler_t *lhp = &vdh.config.lh;
+ lhp->level = LW_LOG_FATAL;
+ lhp->show_log = throw_error;
+ return movie_param.number_of_tracks;
+}
+
+static void setup_timestamp_info( libavsmash_video_decode_handler_t *hp, avxsynth::VideoInfo *vi, uint64_t media_timescale, avxsynth::IScriptEnvironment *env )
+{
+ if( vi->num_frames == 1 )
+ {
+ /* Calculate average framerate. */
+ uint64_t media_duration = lsmash_get_media_duration_from_media_timeline( hp->root, hp->track_ID );
+ if( media_duration == 0 )
+ media_duration = INT32_MAX;
+ reduce_fraction( &media_timescale, &media_duration );
+ vi->fps_numerator = (unsigned int)media_timescale;
+ vi->fps_denominator = (unsigned int)media_duration;
+ return;
+ }
+ lsmash_media_ts_list_t ts_list;
+ if( lsmash_get_media_timestamps( hp->root, hp->track_ID, &ts_list ) )
+ env->ThrowError( "LSMASHVideoSource: failed to get timestamps." );
+ if( ts_list.sample_count != vi->num_frames )
+ env->ThrowError( "LSMASHVideoSource: failed to count number of video samples." );
+ uint32_t composition_sample_delay;
+ if( lsmash_get_max_sample_delay( &ts_list, &composition_sample_delay ) )
+ {
+ lsmash_delete_media_timestamps( &ts_list );
+ env->ThrowError( "LSMASHVideoSource: failed to get composition delay." );
+ }
+ if( composition_sample_delay )
+ {
+ /* Consider composition order for keyframe detection.
+ * Note: sample number for L-SMASH is 1-origin. */
+ hp->order_converter = (order_converter_t *)malloc( (ts_list.sample_count + 1) * sizeof(order_converter_t) );
+ if( !hp->order_converter )
+ {
+ lsmash_delete_media_timestamps( &ts_list );
+ env->ThrowError( "LSMASHVideoSource: failed to allocate memory." );
+ }
+ for( uint32_t i = 0; i < ts_list.sample_count; i++ )
+ ts_list.timestamp[i].dts = i + 1;
+ lsmash_sort_timestamps_composition_order( &ts_list );
+ for( uint32_t i = 0; i < ts_list.sample_count; i++ )
+ hp->order_converter[i + 1].composition_to_decoding = (uint32_t)ts_list.timestamp[i].dts;
+ }
+ /* Calculate average framerate. */
+ uint64_t largest_cts = ts_list.timestamp[1].cts;
+ uint64_t second_largest_cts = ts_list.timestamp[0].cts;
+ uint64_t composition_timebase = ts_list.timestamp[1].cts - ts_list.timestamp[0].cts;
+ for( uint32_t i = 2; i < ts_list.sample_count; i++ )
+ {
+ if( ts_list.timestamp[i].cts == ts_list.timestamp[i - 1].cts )
+ {
+ lsmash_delete_media_timestamps( &ts_list );
+ return;
+ }
+ composition_timebase = get_gcd( composition_timebase, ts_list.timestamp[i].cts - ts_list.timestamp[i - 1].cts );
+ second_largest_cts = largest_cts;
+ largest_cts = ts_list.timestamp[i].cts;
+ }
+ uint64_t reduce = reduce_fraction( &media_timescale, &composition_timebase );
+ uint64_t composition_duration = ((largest_cts - ts_list.timestamp[0].cts) + (largest_cts - second_largest_cts)) / reduce;
+ lsmash_delete_media_timestamps( &ts_list );
+ vi->fps_numerator = (unsigned int)((vi->num_frames * ((double)media_timescale / composition_duration)) * composition_timebase + 0.5);
+ vi->fps_denominator = (unsigned int)composition_timebase;
+}
+
+void LSMASHVideoSource::get_video_track( const char *source, uint32_t track_number, int threads, avxsynth::IScriptEnvironment *env )
+{
+ uint32_t number_of_tracks = open_file( source, env );
+ if( track_number && track_number > number_of_tracks )
+ env->ThrowError( "LSMASHVideoSource: the number of tracks equals %I32u.", number_of_tracks );
+ /* L-SMASH */
+ uint32_t i;
+ lsmash_media_parameters_t media_param;
+ if( track_number == 0 )
+ {
+ /* Get the first video track. */
+ for( i = 1; i <= number_of_tracks; i++ )
+ {
+ vdh.track_ID = lsmash_get_track_ID( vdh.root, i );
+ if( vdh.track_ID == 0 )
+ env->ThrowError( "LSMASHVideoSource: failed to find video track." );
+ lsmash_initialize_media_parameters( &media_param );
+ if( lsmash_get_media_parameters( vdh.root, vdh.track_ID, &media_param ) )
+ env->ThrowError( "LSMASHVideoSource: failed to get media parameters." );
+ if( media_param.handler_type == ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK )
+ break;
+ }
+ if( i > number_of_tracks )
+ env->ThrowError( "LSMASHVideoSource: failed to find video track." );
+ }
+ else
+ {
+ /* Get the desired video track. */
+ vdh.track_ID = lsmash_get_track_ID( vdh.root, track_number );
+ if( vdh.track_ID == 0 )
+ env->ThrowError( "LSMASHVideoSource: failed to find video track." );
+ lsmash_initialize_media_parameters( &media_param );
+ if( lsmash_get_media_parameters( vdh.root, vdh.track_ID, &media_param ) )
+ env->ThrowError( "LSMASHVideoSource: failed to get media parameters." );
+ if( media_param.handler_type != ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK )
+ env->ThrowError( "LSMASHVideoSource: the track you specified is not a video track." );
+ }
+ if( lsmash_construct_timeline( vdh.root, vdh.track_ID ) )
+ env->ThrowError( "LSMASHVideoSource: failed to get construct timeline." );
+ if( get_summaries( vdh.root, vdh.track_ID, &vdh.config ) )
+ env->ThrowError( "LSMASHVideoSource: failed to get summaries." );
+ vi.num_frames = lsmash_get_sample_count_in_media_timeline( vdh.root, vdh.track_ID );
+ setup_timestamp_info( &vdh, &vi, media_param.timescale, env );
+ /* libavformat */
+ for( i = 0; i < format_ctx->nb_streams && format_ctx->streams[i]->codec->codec_type != AVMEDIA_TYPE_VIDEO; i++ );
+ if( i == format_ctx->nb_streams )
+ env->ThrowError( "LSMASHVideoSource: failed to find stream by libavformat." );
+ /* libavcodec */
+ AVStream *stream = format_ctx->streams[i];
+ AVCodecContext *ctx = stream->codec;
+ vdh.config.ctx = ctx;
+ AVCodec *codec = avcodec_find_decoder( ctx->codec_id );
+ if( !codec )
+ env->ThrowError( "LSMASHVideoSource: failed to find %s decoder.", codec->name );
+ ctx->thread_count = threads;
+ if( avcodec_open2( ctx, codec, NULL ) < 0 )
+ env->ThrowError( "LSMASHVideoSource: failed to avcodec_open2." );
+}
+
+void LSMASHVideoSource::prepare_video_decoding
+(
+ int direct_rendering,
+ int stacked_format,
+ enum AVPixelFormat pixel_format,
+ avxsynth::IScriptEnvironment *env
+)
+{
+ vdh.frame_buffer = avcodec_alloc_frame();
+ if( !vdh.frame_buffer )
+ env->ThrowError( "LSMASHVideoSource: failed to allocate video frame buffer." );
+ /* Initialize the video decoder configuration. */
+ codec_configuration_t *config = &vdh.config;
+ config->lh.priv = env;
+ if( initialize_decoder_configuration( vdh.root, vdh.track_ID, config ) )
+ env->ThrowError( "LSMASHVideoSource: failed to initialize the decoder configuration." );
+ /* Set up output format. */
+ config->get_buffer = as_setup_video_rendering( &voh, config->ctx, "LSMASHVideoSource",
+ direct_rendering, stacked_format, pixel_format,
+ config->prefer.width, config->prefer.height );
+ /* Find the first valid video sample. */
+ if( libavsmash_find_first_valid_video_frame( &vdh, vi.num_frames ) < 0 )
+ env->ThrowError( "LSMASHVideoSource: failed to find the first valid video frame." );
+ /* Force seeking at the first reading. */
+ vdh.last_sample_number = vi.num_frames + 1;
+}
+
+avxsynth::PVideoFrame __stdcall LSMASHVideoSource::GetFrame( int n, avxsynth::IScriptEnvironment *env )
+{
+ uint32_t sample_number = n + 1; /* For L-SMASH, sample_number is 1-origin. */
+ codec_configuration_t *config = &vdh.config;
+ config->lh.priv = env;
+ if( config->error )
+ return env->NewVideoFrame( vi );
+ if( libavsmash_get_video_frame( &vdh, sample_number, vi.num_frames ) < 0 )
+ return env->NewVideoFrame( vi );
+ avxsynth::PVideoFrame as_frame;
+ if( make_frame( &voh, config->ctx, vdh.frame_buffer, as_frame, env ) < 0 )
+ env->ThrowError( "LSMASHVideoSource: failed to make a frame." );
+ return as_frame;
+}
+
+LSMASHAudioSource::LSMASHAudioSource
+(
+ const char *source,
+ uint32_t track_number,
+ bool skip_priming,
+ uint64_t channel_layout,
+ int sample_rate,
+ avxsynth::IScriptEnvironment *env
+)
+{
+ memset( &vi, 0, sizeof(avxsynth::VideoInfo) );
+ memset( &adh, 0, sizeof(libavsmash_audio_decode_handler_t) );
+ memset( &aoh, 0, sizeof(libavsmash_audio_output_handler_t) );
+ format_ctx = NULL;
+ get_audio_track( source, track_number, skip_priming, env );
+ lsmash_discard_boxes( adh.root );
+ prepare_audio_decoding( channel_layout, sample_rate, env );
+}
+
+LSMASHAudioSource::~LSMASHAudioSource()
+{
+ libavsmash_cleanup_audio_decode_handler( &adh );
+ libavsmash_cleanup_audio_output_handler( &aoh );
+ if( format_ctx )
+ avformat_close_input( &format_ctx );
+ lsmash_destroy_root( adh.root );
+}
+
+uint32_t LSMASHAudioSource::open_file( const char *source, avxsynth::IScriptEnvironment *env )
+{
+ /* L-SMASH */
+ adh.root = lsmash_open_movie( source, LSMASH_FILE_MODE_READ );
+ if( !adh.root )
+ env->ThrowError( "LSMASHAudioSource: failed to lsmash_open_movie." );
+ lsmash_movie_parameters_t movie_param;
+ lsmash_initialize_movie_parameters( &movie_param );
+ lsmash_get_movie_parameters( adh.root, &movie_param );
+ if( movie_param.number_of_tracks == 0 )
+ env->ThrowError( "LSMASHAudioSource: the number of tracks equals 0." );
+ /* libavformat */
+ av_register_all();
+ avcodec_register_all();
+ if( avformat_open_input( &format_ctx, source, NULL, NULL ) )
+ env->ThrowError( "LSMASHAudioSource: failed to avformat_open_input." );
+ if( avformat_find_stream_info( format_ctx, NULL ) < 0 )
+ env->ThrowError( "LSMASHAudioSource: failed to avformat_find_stream_info." );
+ /* */
+ lw_log_handler_t *lhp = &adh.config.lh;
+ lhp->level = LW_LOG_FATAL;
+ lhp->show_log = throw_error;
+ return movie_param.number_of_tracks;
+}
+
+static int64_t get_start_time( lsmash_root_t *root, uint32_t track_ID )
+{
+ /* Consider start time of this media if any non-empty edit is present. */
+ uint32_t edit_count = lsmash_count_explicit_timeline_map( root, track_ID );
+ for( uint32_t edit_number = 1; edit_number <= edit_count; edit_number++ )
+ {
+ lsmash_edit_t edit;
+ if( lsmash_get_explicit_timeline_map( root, track_ID, edit_number, &edit ) )
+ return 0;
+ if( edit.duration == 0 )
+ return 0; /* no edits */
+ if( edit.start_time >= 0 )
+ return edit.start_time;
+ }
+ return 0;
+}
+
+static char *duplicate_as_string( void *src, size_t length )
+{
+ char *dst = new char[length + 1];
+ if( !dst )
+ return NULL;
+ memcpy( dst, src, length );
+ dst[length] = '\0';
+ return dst;
+}
+
+void LSMASHAudioSource::get_audio_track( const char *source, uint32_t track_number, bool skip_priming, avxsynth::IScriptEnvironment *env )
+{
+ uint32_t number_of_tracks = open_file( source, env );
+ if( track_number && track_number > number_of_tracks )
+ env->ThrowError( "LSMASHAudioSource: the number of tracks equals %I32u.", number_of_tracks );
+ /* L-SMASH */
+ uint32_t i;
+ lsmash_media_parameters_t media_param;
+ if( track_number == 0 )
+ {
+ /* Get the first audio track. */
+ for( i = 1; i <= number_of_tracks; i++ )
+ {
+ adh.track_ID = lsmash_get_track_ID( adh.root, i );
+ if( adh.track_ID == 0 )
+ env->ThrowError( "LSMASHAudioSource: failed to find audio track." );
+ lsmash_initialize_media_parameters( &media_param );
+ if( lsmash_get_media_parameters( adh.root, adh.track_ID, &media_param ) )
+ env->ThrowError( "LSMASHAudioSource: failed to get media parameters." );
+ if( media_param.handler_type == ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK )
+ break;
+ }
+ if( i > number_of_tracks )
+ env->ThrowError( "LSMASHAudioSource: failed to find audio track." );
+ }
+ else
+ {
+ /* Get the desired audio track. */
+ adh.track_ID = lsmash_get_track_ID( adh.root, track_number );
+ if( adh.track_ID == 0 )
+ env->ThrowError( "LSMASHAudioSource: failed to find audio track." );
+ lsmash_initialize_media_parameters( &media_param );
+ if( lsmash_get_media_parameters( adh.root, adh.track_ID, &media_param ) )
+ env->ThrowError( "LSMASHAudioSource: failed to get media parameters." );
+ if( media_param.handler_type != ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK )
+ env->ThrowError( "LSMASHAudioSource: the track you specified is not an audio track." );
+ }
+ if( lsmash_construct_timeline( adh.root, adh.track_ID ) )
+ env->ThrowError( "LSMASHAudioSource: failed to get construct timeline." );
+ if( get_summaries( adh.root, adh.track_ID, &adh.config ) )
+ env->ThrowError( "LSMASHAudioSource: failed to get summaries." );
+ adh.frame_count = lsmash_get_sample_count_in_media_timeline( adh.root, adh.track_ID );
+ vi.num_audio_samples = lsmash_get_media_duration_from_media_timeline( adh.root, adh.track_ID );
+ if( skip_priming )
+ {
+ uint32_t itunes_metadata_count = lsmash_count_itunes_metadata( adh.root );
+ for( i = 1; i <= itunes_metadata_count; i++ )
+ {
+ lsmash_itunes_metadata_t metadata;
+ if( lsmash_get_itunes_metadata( adh.root, i, &metadata ) < 0 )
+ continue;
+ if( metadata.item != ITUNES_METADATA_ITEM_CUSTOM
+ || (metadata.type != ITUNES_METADATA_TYPE_STRING && metadata.type != ITUNES_METADATA_TYPE_BINARY)
+ || !metadata.meaning || !metadata.name
+ || memcmp( "com.apple.iTunes", metadata.meaning, strlen( metadata.meaning ) )
+ || memcmp( "iTunSMPB", metadata.name, strlen( metadata.name ) ) )
+ {
+ lsmash_cleanup_itunes_metadata( &metadata );
+ continue;
+ }
+ char *value = NULL;
+ if( metadata.type == ITUNES_METADATA_TYPE_STRING )
+ {
+ int length = strlen( metadata.value.string );
+ if( length >= 116 )
+ value = duplicate_as_string( metadata.value.string, length );
+ }
+ else /* metadata.type == ITUNES_METADATA_TYPE_BINARY */
+ {
+ if( metadata.value.binary.size >= 116 )
+ value = duplicate_as_string( metadata.value.binary.data, metadata.value.binary.size );
+ }
+ lsmash_cleanup_itunes_metadata( &metadata );
+ if( !value )
+ continue;
+ uint32_t dummy[9];
+ uint32_t priming_samples;
+ uint32_t padding;
+ uint64_t duration;
+ if( 12 != sscanf( value, " %I32x %I32x %I32x %I64x %I32x %I32x %I32x %I32x %I32x %I32x %I32x %I32x",
+ &dummy[0], &priming_samples, &padding, &duration, &dummy[1], &dummy[2],
+ &dummy[3], &dummy[4], &dummy[5], &dummy[6], &dummy[7], &dummy[8] ) )
+ {
+ delete [] value;
+ continue;
+ }
+ delete [] value;
+ adh.implicit_preroll = 1;
+ aoh.skip_decoded_samples = priming_samples;
+ vi.num_audio_samples = duration + priming_samples;
+ break;
+ }
+ if( aoh.skip_decoded_samples == 0 )
+ {
+ uint32_t ctd_shift;
+ if( lsmash_get_composition_to_decode_shift_from_media_timeline( adh.root, adh.track_ID, &ctd_shift ) )
+ env->ThrowError( "LSMASHAudioSource: failed to get the timeline shift." );
+ aoh.skip_decoded_samples = ctd_shift + get_start_time( adh.root, adh.track_ID );
+ }
+ }
+ /* libavformat */
+ for( i = 0; i < format_ctx->nb_streams && format_ctx->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO; i++ );
+ if( i == format_ctx->nb_streams )
+ env->ThrowError( "LSMASHAudioSource: failed to find stream by libavformat." );
+ /* libavcodec */
+ AVStream *stream = format_ctx->streams[i];
+ AVCodecContext *ctx = stream->codec;
+ adh.config.ctx = ctx;
+ AVCodec *codec = avcodec_find_decoder( ctx->codec_id );
+ if( !codec )
+ env->ThrowError( "LSMASHAudioSource: failed to find %s decoder.", codec->name );
+ ctx->thread_count = 0;
+ if( avcodec_open2( ctx, codec, NULL ) < 0 )
+ env->ThrowError( "LSMASHAudioSource: failed to avcodec_open2." );
+}
+
+void LSMASHAudioSource::prepare_audio_decoding
+(
+ uint64_t channel_layout,
+ int sample_rate,
+ avxsynth::IScriptEnvironment *env
+)
+{
+ adh.frame_buffer = avcodec_alloc_frame();
+ if( !adh.frame_buffer )
+ env->ThrowError( "LSMASHAudioSource: failed to allocate audio frame buffer." );
+ /* Initialize the audio decoder configuration. */
+ codec_configuration_t *config = &adh.config;
+ config->lh.priv = env;
+ if( initialize_decoder_configuration( adh.root, adh.track_ID, config ) )
+ env->ThrowError( "LSMASHAudioSource: failed to initialize the decoder configuration." );
+ aoh.output_channel_layout = config->prefer.channel_layout;
+ aoh.output_sample_format = config->prefer.sample_format;
+ aoh.output_sample_rate = config->prefer.sample_rate;
+ aoh.output_bits_per_sample = config->prefer.bits_per_sample;
+ as_setup_audio_rendering( &aoh, config->ctx, &vi, env, "LSMASHAudioSource", channel_layout, sample_rate );
+ /* Count the number of PCM audio samples. */
+ vi.num_audio_samples = libavsmash_count_overall_pcm_samples( &adh, aoh.output_sample_rate, &aoh.skip_decoded_samples );
+ if( vi.num_audio_samples == 0 )
+ env->ThrowError( "LSMASHAudioSource: no valid audio frame." );
+ /* Force seeking at the first reading. */
+ adh.next_pcm_sample_number = vi.num_audio_samples + 1;
+}
+
+void __stdcall LSMASHAudioSource::GetAudio( void *buf, avxsynth::__int64 start, avxsynth::__int64 wanted_length, avxsynth::IScriptEnvironment *env )
+{
+ adh.config.lh.priv = env;
+ return (void)libavsmash_get_pcm_audio_samples( &adh, &aoh, buf, start, wanted_length );
+}
+
+extern avxsynth::AVSValue __cdecl CreateLSMASHVideoSource( avxsynth::AVSValue args, void *user_data, avxsynth::IScriptEnvironment *env )
+{
+#ifdef NDEBUG
+ av_log_set_level( AV_LOG_QUIET );
+#endif
+ const char *source = args[0].AsString();
+ uint32_t track_number = args[1].AsInt( 0 );
+ int threads = args[2].AsInt( 0 );
+ int seek_mode = args[3].AsInt( 0 );
+ uint32_t forward_seek_threshold = args[4].AsInt( 10 );
+ int direct_rendering = args[5].AsBool( false ) ? 1 : 0;
+ int stacked_format = args[6].AsBool( false ) ? 1 : 0;
+ enum AVPixelFormat pixel_format = get_av_output_pixel_format( args[7].AsString( NULL ) );
+ threads = threads >= 0 ? threads : 0;
+ seek_mode = CLIP_VALUE( seek_mode, 0, 2 );
+ forward_seek_threshold = CLIP_VALUE( forward_seek_threshold, 1, 999 );
+ direct_rendering &= (pixel_format == AV_PIX_FMT_NONE);
+ return new LSMASHVideoSource( source, track_number, threads, seek_mode, forward_seek_threshold,
+ direct_rendering, stacked_format, pixel_format, env );
+}
+
+extern avxsynth::AVSValue __cdecl CreateLSMASHAudioSource( avxsynth::AVSValue args, void *user_data, avxsynth::IScriptEnvironment *env )
+{
+#ifdef NDEBUG
+ av_log_set_level( AV_LOG_QUIET );
+#endif
+ const char *source = args[0].AsString();
+ uint32_t track_number = args[1].AsInt( 0 );
+ bool skip_priming = args[2].AsBool( true );
+ const char *layout_string = args[3].AsString( NULL );
+ int sample_rate = args[4].AsInt( 0 );
+ uint64_t channel_layout = layout_string ? av_get_channel_layout( layout_string ) : 0;
+ return new LSMASHAudioSource( source, track_number, skip_priming, channel_layout, sample_rate, env );
+}
diff --git a/AvxSynth/libavsmash_source.h b/AvxSynth/libavsmash_source.h
new file mode 100644
index 0000000..3e4843f
--- /dev/null
+++ b/AvxSynth/libavsmash_source.h
@@ -0,0 +1,117 @@
+/*****************************************************************************
+ * libavsmash_source.h
+ *****************************************************************************
+ * Copyright (C) 2012-2013 L-SMASH Works project
+ *
+ * Authors: Yusuke Nakamura <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *****************************************************************************/
+
+/* This file is available under an ISC license.
+ * However, when distributing its binary file, it will be under LGPL or GPL. */
+
+#include "../common/libavsmash.h"
+#include "../common/libavsmash_video.h"
+#include "../common/libavsmash_audio.h"
+#include "avxplugin.h"
+
+class LSMASHVideoSource : public avxsynth::IClip
+{
+private:
+ avxsynth::VideoInfo vi;
+ libavsmash_video_decode_handler_t vdh;
+ libavsmash_video_output_handler_t voh;
+ AVFormatContext *format_ctx;
+ uint32_t open_file
+ (
+ const char *source,
+ avxsynth::IScriptEnvironment *env
+ );
+ void get_video_track
+ (
+ const char *source,
+ uint32_t track_number,
+ int threads,
+ avxsynth::IScriptEnvironment *env
+ );
+ void prepare_video_decoding
+ (
+ int direct_rendering,
+ int stacked_format,
+ enum AVPixelFormat pixel_format,
+ avxsynth::IScriptEnvironment *env
+ );
+public:
+ LSMASHVideoSource
+ (
+ const char *source,
+ uint32_t track_number,
+ int threads,
+ int seek_mode,
+ uint32_t forward_seek_threshold,
+ int direct_rendering,
+ int stacked_format,
+ enum AVPixelFormat pixel_format,
+ avxsynth::IScriptEnvironment *env
+ );
+ ~LSMASHVideoSource();
+ avxsynth::PVideoFrame __stdcall GetFrame( int n, avxsynth::IScriptEnvironment *env );
+ bool __stdcall GetParity( int n ) { return false; }
+ void __stdcall GetAudio( void *buf, avxsynth::__int64 start, avxsynth::__int64 count, avxsynth::IScriptEnvironment *env ) {}
+ void __stdcall SetCacheHints( int cachehints, size_t frame_range ) {}
+ const avxsynth::VideoInfo& __stdcall GetVideoInfo() { return vi; }
+};
+
+class LSMASHAudioSource : public avxsynth::IClip
+{
+private:
+ avxsynth::VideoInfo vi;
+ libavsmash_audio_decode_handler_t adh;
+ libavsmash_audio_output_handler_t aoh;
+ AVFormatContext *format_ctx;
+ uint32_t open_file
+ (
+ const char *source,
+ avxsynth::IScriptEnvironment *env
+ );
+ void get_audio_track
+ (
+ const char *source,
+ uint32_t track_number,
+ bool skip_priming,
+ avxsynth::IScriptEnvironment *env
+ );
+ void prepare_audio_decoding
+ (
+ uint64_t channel_layout,
+ int sample_rate,
+ avxsynth::IScriptEnvironment *env
+ );
+public:
+ LSMASHAudioSource
+ (
+ const char *source,
+ uint32_t track_number,
+ bool skip_priming,
+ uint64_t channel_layout,
+ int sample_rate,
+ avxsynth::IScriptEnvironment *env
+ );
+ ~LSMASHAudioSource();
+ avxsynth::PVideoFrame __stdcall GetFrame( int n, avxsynth::IScriptEnvironment *env ) { return NULL; }
+ bool __stdcall GetParity( int n ) { return false; }
+ void __stdcall GetAudio( void *buf, avxsynth::__int64 start, avxsynth::__int64 wanted_length, avxsynth::IScriptEnvironment *env );
+ void __stdcall SetCacheHints( int cachehints, size_t frame_range ) {}
+ const avxsynth::VideoInfo& __stdcall GetVideoInfo() { return vi; }
+};
diff --git a/AvxSynth/lsmashsource.cpp b/AvxSynth/lsmashsource.cpp
new file mode 100644
index 0000000..d862385
--- /dev/null
+++ b/AvxSynth/lsmashsource.cpp
@@ -0,0 +1,88 @@
+/*****************************************************************************
+ * lsmashsource.cpp
+ *****************************************************************************
+ * Copyright (C) 2012-2013 L-SMASH Works project
+ *
+ * Authors: Yusuke Nakamura <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *****************************************************************************/
+
+/* This file is available under an ISC license.
+ * However, when distributing its binary file, it will be under LGPL or GPL. */
+
+#include <stdio.h>
+
+#include "lsmashsource.h"
+
+void throw_error
+(
+ lw_log_handler_t *lhp,
+ lw_log_level level,
+ const char *format,
+ ...
+)
+{
+ char message[256];
+ va_list args;
+ va_start( args, format );
+ int written = lw_log_write_message( lhp, level, message, format, args );
+ va_end( args );
+ if( written )
+ {
+ avxsynth::IScriptEnvironment *env = (avxsynth::IScriptEnvironment *)lhp->priv;
+ env->ThrowError( (const char *)message );
+ }
+}
+
+extern avxsynth::AVSValue __cdecl CreateLSMASHVideoSource( avxsynth::AVSValue args, void *user_data, avxsynth::IScriptEnvironment *env );
+extern avxsynth::AVSValue __cdecl CreateLSMASHAudioSource( avxsynth::AVSValue args, void *user_data, avxsynth::IScriptEnvironment *env );
+extern avxsynth::AVSValue __cdecl CreateLWLibavVideoSource( avxsynth::AVSValue args, void *user_data, avxsynth::IScriptEnvironment *env );
+extern avxsynth::AVSValue __cdecl CreateLWLibavAudioSource( avxsynth::AVSValue args, void *user_data, avxsynth::IScriptEnvironment *env );
+
+extern "C" __declspec(dllexport) const char * __stdcall AvisynthPluginInit2( avxsynth::IScriptEnvironment *env )
+{
+ /* LSMASHVideoSource */
+ env->AddFunction
+ (
+ "LSMASHVideoSource",
+ "[source]s[track]i[threads]i[seek_mode]i[seek_threshold]i[dr]b[stacked]b[format]s",
+ CreateLSMASHVideoSource,
+ 0
+ );
+ /* LSMASHAudioSource */
+ env->AddFunction
+ (
+ "LSMASHAudioSource",
+ "[source]s[track]i[skip_priming]b[layout]s[rate]i",
+ CreateLSMASHAudioSource,
+ 0
+ );
+ /* LWLibavVideoSource */
+ env->AddFunction
+ (
+ "LWLibavVideoSource",
+ "[source]s[stream_index]i[threads]i[cache]b[seek_mode]i[seek_threshold]i[dr]b[repeat]b[dominance]i[stacked]b[format]s",
+ CreateLWLibavVideoSource,
+ 0
+ );
+ /* LWLibavAudioSource */
+ env->AddFunction
+ (
+ "LWLibavAudioSource",
+ "[source]s[stream_index]i[cache]b[av_sync]b[layout]s[rate]i",
+ CreateLWLibavAudioSource,
+ 0
+ );
+ return "LSMASHSource";
+}
diff --git a/AvxSynth/lsmashsource.h b/AvxSynth/lsmashsource.h
new file mode 100644
index 0000000..a835356
--- /dev/null
+++ b/AvxSynth/lsmashsource.h
@@ -0,0 +1,35 @@
+/*****************************************************************************
+ * lsmashsource.h
+ *****************************************************************************
+ * Copyright (C) 2012-2013 L-SMASH Works project
+ *
+ * Authors: Yusuke Nakamura <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *****************************************************************************/
+
+/* This file is available under an ISC license.
+ * However, when distributing its binary file, it will be under LGPL or GPL. */
+
+#include "../common/cpp_compat.h"
+#include "../common/utils.h"
+
+#include "avxplugin.h"
+
+void throw_error
+(
+ lw_log_handler_t *lhp,
+ lw_log_level level,
+ const char *format,
+ ...
+);
diff --git a/AvxSynth/lwlibav_source.cpp b/AvxSynth/lwlibav_source.cpp
new file mode 100644
index 0000000..3be4d4c
--- /dev/null
+++ b/AvxSynth/lwlibav_source.cpp
@@ -0,0 +1,310 @@
+/*****************************************************************************
+ * lwlibav_source.cpp
+ *****************************************************************************
+ * Copyright (C) 2013 L-SMASH Works project
+ *
+ * Authors: Yusuke Nakamura <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *****************************************************************************/
+
+/* This file is available under an ISC license.
+ * However, when distributing its binary file, it will be under LGPL or GPL. */
+
+#include "lsmashsource.h"
+
+extern "C"
+{
+/* Libav
+ * The binary file will be LGPLed or GPLed. */
+#include <libavformat/avformat.h> /* Codec specific info importer */
+#include <libavcodec/avcodec.h> /* Decoder */
+#include <libswscale/swscale.h> /* Colorspace converter */
+#include <libavresample/avresample.h> /* Audio resampler */
+#include <libavutil/imgutils.h>
+#include <libavutil/mem.h>
+#include <libavutil/opt.h>
+}
+
+#include "video_output.h"
+#include "audio_output.h"
+#include "lwlibav_source.h"
+
+LWLibavVideoSource::LWLibavVideoSource
+(
+ lwlibav_option_t *opt,
+ int seek_mode,
+ uint32_t forward_seek_threshold,
+ int direct_rendering,
+ int stacked_format,
+ enum AVPixelFormat pixel_format,
+ avxsynth::IScriptEnvironment *env
+)
+{
+ memset( &vi, 0, sizeof(avxsynth::VideoInfo) );
+ memset( &lwh, 0, sizeof(lwlibav_file_handler_t) );
+ memset( &vdh, 0, sizeof(lwlibav_video_decode_handler_t) );
+ memset( &voh, 0, sizeof(lwlibav_video_output_handler_t) );
+ vdh.seek_mode = seek_mode;
+ vdh.forward_seek_threshold = forward_seek_threshold;
+ as_video_output_handler_t *as_vohp = (as_video_output_handler_t *)lw_malloc_zero( sizeof(as_video_output_handler_t) );
+ if( !as_vohp )
+ env->ThrowError( "LWLibavVideoSource: failed to allocate the AviSynth video output handler." );
+ as_vohp->vi = &vi;
+ as_vohp->env = env;
+ voh.private_handler = as_vohp;
+ voh.free_private_handler = as_free_video_output_handler;
+ /* Set up error handler. */
+ lw_log_handler_t lh;
+ lh.level = LW_LOG_FATAL; /* Ignore other than fatal error. */
+ lh.priv = env;
+ lh.show_log = throw_error;
+ /* Set up progress indicator. */
+ progress_indicator_t indicator;
+ indicator.open = NULL;
+ indicator.update = NULL;
+ indicator.close = NULL;
+ /* Construct index. */
+ lwlibav_audio_decode_handler_t adh = { 0 };
+ lwlibav_audio_output_handler_t aoh = { 0 };
+ int ret = lwlibav_construct_index( &lwh, &vdh, &voh, &adh, &aoh, &lh, opt, &indicator, NULL );
+ lwlibav_cleanup_audio_decode_handler( &adh );
+ lwlibav_cleanup_audio_output_handler( &aoh );
+ if( ret < 0 )
+ env->ThrowError( "LWLibavVideoSource: failed to construct index." );
+ /* Get the desired video track. */
+ if( lwlibav_get_desired_video_track( lwh.file_path, &vdh, lwh.threads ) < 0 )
+ env->ThrowError( "LWLibavVideoSource: failed to get the video track." );
+ vdh.lh = lh;
+ vi.num_frames = voh.frame_count;
+ /* Set average framerate. */
+ int fps_num;
+ int fps_den;
+ lwlibav_setup_timestamp_info( &lwh, &vdh, &voh, &fps_num, &fps_den );
+ vi.fps_numerator = (unsigned int)fps_num;
+ vi.fps_denominator = (unsigned int)fps_den;
+ /* */
+ prepare_video_decoding( direct_rendering, stacked_format, pixel_format, env );
+}
+
+LWLibavVideoSource::~LWLibavVideoSource()
+{
+ lwlibav_cleanup_video_decode_handler( &vdh );
+ lwlibav_cleanup_video_output_handler( &voh );
+ if( lwh.file_path )
+ free( lwh.file_path );
+}
+
+void LWLibavVideoSource::prepare_video_decoding
+(
+ int direct_rendering,
+ int stacked_format,
+ enum AVPixelFormat pixel_format,
+ avxsynth::IScriptEnvironment *env
+)
+{
+ vdh.lh.priv = env;
+ /* Import AVIndexEntrys. */
+ if( lwlibav_import_av_index_entry( (lwlibav_decode_handler_t *)&vdh ) < 0 )
+ env->ThrowError( "LWLibavVideoSource: failed to import AVIndexEntrys for video." );
+ /* Set up output format. */
+ vdh.ctx->width = vdh.initial_width;
+ vdh.ctx->height = vdh.initial_height;
+ vdh.ctx->pix_fmt = vdh.initial_pix_fmt;
+ vdh.ctx->colorspace = vdh.initial_colorspace;
+ vdh.exh.get_buffer = as_setup_video_rendering( &voh, vdh.ctx, "LWLibavVideoSource",
+ direct_rendering, stacked_format, pixel_format,
+ vdh.max_width, vdh.max_height );
+ /* Find the first valid video sample. */
+ if( lwlibav_find_first_valid_video_frame( &vdh ) < 0 )
+ env->ThrowError( "LWLibavVideoSource: failed to find the first valid video frame." );
+ /* Force seeking at the first reading. */
+ vdh.last_frame_number = vi.num_frames + 1;
+}
+
+avxsynth::PVideoFrame __stdcall LWLibavVideoSource::GetFrame( int n, avxsynth::IScriptEnvironment *env )
+{
+ uint32_t frame_number = n + 1; /* frame_number is 1-origin. */
+ vdh.lh.priv = env;
+ if( vdh.error )
+ return env->NewVideoFrame( vi );
+ if( lwlibav_get_video_frame( &vdh, &voh, frame_number ) < 0 )
+ return env->NewVideoFrame( vi );
+ avxsynth::PVideoFrame as_frame;
+ if( make_frame( &voh, vdh.ctx, vdh.frame_buffer, as_frame, env ) < 0 )
+ env->ThrowError( "LWLibavVideoSource: failed to make a frame." );
+ return as_frame;
+}
+
+bool __stdcall LWLibavVideoSource::GetParity( int n )
+{
+ uint32_t frame_number = n + 1; /* frame_number is 1-origin. */
+ if( !voh.repeat_control )
+ return vdh.frame_list[frame_number].field_info == LW_FIELD_INFO_TOP ? true : false;
+ uint32_t t = voh.frame_order_list[frame_number].top;
+ uint32_t b = voh.frame_order_list[frame_number].bottom;
+ return t < b ? true : false;
+}
+
+LWLibavAudioSource::LWLibavAudioSource
+(
+ lwlibav_option_t *opt,
+ uint64_t channel_layout,
+ int sample_rate,
+ avxsynth::IScriptEnvironment *env
+)
+{
+ memset( &vi, 0, sizeof(avxsynth::VideoInfo) );
+ memset( &lwh, 0, sizeof(lwlibav_file_handler_t) );
+ memset( &adh, 0, sizeof(lwlibav_audio_decode_handler_t) );
+ memset( &aoh, 0, sizeof(lwlibav_audio_output_handler_t) );
+ /* Set up error handler. */
+ lw_log_handler_t lh;
+ lh.level = LW_LOG_FATAL; /* Ignore other than fatal error. */
+ lh.priv = env;
+ lh.show_log = throw_error;
+ /* Set up progress indicator. */
+ progress_indicator_t indicator;
+ indicator.open = NULL;
+ indicator.update = NULL;
+ indicator.close = NULL;
+ /* Construct index. */
+ lwlibav_video_decode_handler_t vdh = { 0 };
+ lwlibav_video_output_handler_t voh = { 0 };
+ if( lwlibav_construct_index( &lwh, &vdh, &voh, &adh, &aoh, &lh, opt, &indicator, NULL ) < 0 )
+ env->ThrowError( "LWLibavAudioSource: failed to get construct index." );
+ lwlibav_cleanup_video_decode_handler( &vdh );
+ lwlibav_cleanup_video_output_handler( &voh );
+ /* Get the desired video track. */
+ if( lwlibav_get_desired_audio_track( lwh.file_path, &adh, lwh.threads ) < 0 )
+ env->ThrowError( "LWLibavAudioSource: failed to get the audio track." );
+ adh.lh = lh;
+ prepare_audio_decoding( channel_layout, sample_rate, env );
+}
+
+LWLibavAudioSource::~LWLibavAudioSource()
+{
+ lwlibav_cleanup_audio_decode_handler( &adh );
+ lwlibav_cleanup_audio_output_handler( &aoh );
+ if( lwh.file_path )
+ free( lwh.file_path );
+}
+
+void LWLibavAudioSource::prepare_audio_decoding
+(
+ uint64_t channel_layout,
+ int sample_rate,
+ avxsynth::IScriptEnvironment *env
+)
+{
+ adh.lh.priv = env;
+ /* Import AVIndexEntrys. */
+ if( lwlibav_import_av_index_entry( (lwlibav_decode_handler_t *)&adh ) < 0 )
+ env->ThrowError( "LWLibavAudioSource: failed to import AVIndexEntrys for audio." );
+ /* */
+ avcodec_get_frame_defaults( adh.frame_buffer );
+ as_setup_audio_rendering( &aoh, adh.ctx, &vi, env, "LWLibavAudioSource", channel_layout, sample_rate );
+ /* Count the number of PCM audio samples. */
+ vi.num_audio_samples = lwlibav_count_overall_pcm_samples( &adh, aoh.output_sample_rate );
+ if( vi.num_audio_samples == 0 )
+ env->ThrowError( "LWLibavAudioSource: no valid audio frame." );
+ if( lwh.av_gap && aoh.output_sample_rate != adh.ctx->sample_rate )
+ lwh.av_gap = ((int64_t)lwh.av_gap * aoh.output_sample_rate - 1) / adh.ctx->sample_rate + 1;
+ vi.num_audio_samples += lwh.av_gap;
+ /* Force seeking at the first reading. */
+ adh.next_pcm_sample_number = vi.num_audio_samples + 1;
+}
+
+int LWLibavAudioSource::delay_audio( int64_t *start, int64_t wanted_length )
+{
+ /* Even if start become negative, its absolute value shall be equal to wanted_length or smaller. */
+ int64_t end = *start + wanted_length;
+ int64_t audio_delay = lwh.av_gap;
+ if( *start < audio_delay && end <= audio_delay )
+ {
+ adh.next_pcm_sample_number = vi.num_audio_samples + 1; /* Force seeking at the next access for valid audio frame. */
+ return 0;
+ }
+ *start -= audio_delay;
+ return 1;
+}
+
+void __stdcall LWLibavAudioSource::GetAudio( void *buf, avxsynth::__int64 start, avxsynth::__int64 wanted_length, avxsynth::IScriptEnvironment *env )
+{
+ adh.lh.priv = env;
+ if( delay_audio( &start, wanted_length ) )
+ return (void)lwlibav_get_pcm_audio_samples( &adh, &aoh, buf, start, wanted_length );
+ uint8_t silence = vi.sample_type == avxsynth::SAMPLE_INT8 ? 128 : 0;
+ memset( buf, silence, (size_t)(wanted_length * aoh.output_block_align) );
+}
+
+extern avxsynth::AVSValue __cdecl CreateLWLibavVideoSource( avxsynth::AVSValue args, void *user_data, avxsynth::IScriptEnvironment *env )
+{
+#ifdef NDEBUG
+ av_log_set_level( AV_LOG_QUIET );
+#endif
+ const char *source = args[0].AsString();
+ int stream_index = args[1].AsInt( -1 );
+ int threads = args[2].AsInt( 0 );
+ int no_create_index = args[3].AsBool( true ) ? 0 : 1;
+ int seek_mode = args[4].AsInt( 0 );
+ uint32_t forward_seek_threshold = args[5].AsInt( 10 );
+ int direct_rendering = args[6].AsBool( false ) ? 1 : 0;
+ int apply_repeat_flag = args[7].AsBool( false ) ? 1 : 0;
+ int field_dominance = args[8].AsInt( 0 );
+ int stacked_format = args[9].AsBool( false ) ? 1 : 0;
+ enum AVPixelFormat pixel_format = get_av_output_pixel_format( args[10].AsString( NULL ) );
+ /* Set LW-Libav options. */
+ lwlibav_option_t opt;
+ opt.file_path = source;
+ opt.threads = threads >= 0 ? threads : 0;
+ opt.av_sync = 0;
+ opt.no_create_index = no_create_index;
+ opt.force_video = (stream_index >= 0);
+ opt.force_video_index = stream_index >= 0 ? stream_index : -1;
+ opt.force_audio = 0;
+ opt.force_audio_index = -1;
+ opt.apply_repeat_flag = apply_repeat_flag;
+ opt.field_dominance = CLIP_VALUE( field_dominance, 0, 2 ); /* 0: Obey source flags, 1: TFF, 2: BFF */
+ seek_mode = CLIP_VALUE( seek_mode, 0, 2 );
+ forward_seek_threshold = CLIP_VALUE( forward_seek_threshold, 1, 999 );
+ direct_rendering &= (pixel_format == AV_PIX_FMT_NONE);
+ return new LWLibavVideoSource( &opt, seek_mode, forward_seek_threshold, direct_rendering, stacked_format, pixel_format, env );
+}
+
+extern avxsynth::AVSValue __cdecl CreateLWLibavAudioSource( avxsynth::AVSValue args, void *user_data, avxsynth::IScriptEnvironment *env )
+{
+#ifdef NDEBUG
+ av_log_set_level( AV_LOG_QUIET );
+#endif
+ const char *source = args[0].AsString();
+ int stream_index = args[1].AsInt( -1 );
+ int no_create_index = args[2].AsBool( true ) ? 0 : 1;
+ int av_sync = args[3].AsBool( false ) ? 1 : 0;
+ const char *layout_string = args[4].AsString( NULL );
+ uint32_t sample_rate = args[5].AsInt( 0 );
+ /* Set LW-Libav options. */
+ lwlibav_option_t opt;
+ opt.file_path = source;
+ opt.threads = 0;
+ opt.av_sync = av_sync;
+ opt.no_create_index = no_create_index;
+ opt.force_video = 0;
+ opt.force_video_index = -1;
+ opt.force_audio = (stream_index >= 0);
+ opt.force_audio_index = stream_index >= 0 ? stream_index : -1;
+ opt.apply_repeat_flag = 0;
+ opt.field_dominance = 0;
+ uint64_t channel_layout = layout_string ? av_get_channel_layout( layout_string ) : 0;
+ return new LWLibavAudioSource( &opt, channel_layout, sample_rate, env );
+}
diff --git a/AvxSynth/lwlibav_source.h b/AvxSynth/lwlibav_source.h
new file mode 100644
index 0000000..f144201
--- /dev/null
+++ b/AvxSynth/lwlibav_source.h
@@ -0,0 +1,93 @@
+/*****************************************************************************
+ * lwlibav_source.h
+ *****************************************************************************
+ * Copyright (C) 2013 L-SMASH Works project
+ *
+ * Authors: Yusuke Nakamura <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *****************************************************************************/
+
+/* This file is available under an ISC license.
+ * However, when distributing its binary file, it will be under LGPL or GPL. */
+
+#define NO_PROGRESS_HANDLER
+
+#include "../common/progress.h"
+#include "../common/lwlibav_dec.h"
+#include "../common/lwlibav_video.h"
+#include "../common/lwlibav_audio.h"
+#include "../common/lwindex.h"
+
+class LWLibavVideoSource : public avxsynth::IClip
+{
+private:
+ avxsynth::VideoInfo vi;
+ lwlibav_file_handler_t lwh;
+ lwlibav_video_decode_handler_t vdh;
+ lwlibav_video_output_handler_t voh;
+ void prepare_video_decoding
+ (
+ int direct_rendering,
+ int stacked_format,
+ enum AVPixelFormat pixel_format,
+ avxsynth::IScriptEnvironment *env
+ );
+public:
+ LWLibavVideoSource
+ (
+ lwlibav_option_t *opt,
+ int seek_mode,
+ uint32_t forward_seek_threshold,
+ int direct_rendering,
+ int stacked_format,
+ enum AVPixelFormat pixel_format,
+ avxsynth::IScriptEnvironment *env
+ );
+ ~LWLibavVideoSource();
+ avxsynth::PVideoFrame __stdcall GetFrame( int n, avxsynth::IScriptEnvironment *env );
+ bool __stdcall GetParity( int n );
+ void __stdcall GetAudio( void *buf, avxsynth::__int64 start, avxsynth::__int64 count, avxsynth::IScriptEnvironment *env ) {}
+ void __stdcall SetCacheHints( int cachehints, size_t frame_range ) {}
+ const avxsynth::VideoInfo& __stdcall GetVideoInfo() { return vi; }
+};
+
+class LWLibavAudioSource : public avxsynth::IClip
+{
+private:
+ avxsynth::VideoInfo vi;
+ lwlibav_file_handler_t lwh;
+ lwlibav_audio_decode_handler_t adh;
+ lwlibav_audio_output_handler_t aoh;
+ void prepare_audio_decoding
+ (
+ uint64_t channel_layout,
+ int sample_rate,
+ avxsynth::IScriptEnvironment *env
+ );
+ int delay_audio( int64_t *start, int64_t wanted_length );
+public:
+ LWLibavAudioSource
+ (
+ lwlibav_option_t *opt,
+ uint64_t channel_layout,
+ int sample_rate,
+ avxsynth::IScriptEnvironment *env
+ );
+ ~LWLibavAudioSource();
+ avxsynth::PVideoFrame __stdcall GetFrame( int n, avxsynth::IScriptEnvironment *env ) { return NULL; }
+ bool __stdcall GetParity( int n ) { return false; }
+ void __stdcall GetAudio( void *buf, avxsynth::__int64 start, avxsynth::__int64 wanted_length, avxsynth::IScriptEnvironment *env );
+ void __stdcall SetCacheHints( int cachehints, size_t frame_range ) {}
+ const avxsynth::VideoInfo& __stdcall GetVideoInfo() { return vi; }
+};
diff --git a/AvxSynth/video_output.cpp b/AvxSynth/video_output.cpp
new file mode 100644
index 0000000..d40d0cb
--- /dev/null
+++ b/AvxSynth/video_output.cpp
@@ -0,0 +1,673 @@
+/*****************************************************************************
+ * video_output.cpp
+ *****************************************************************************
+ * Copyright (C) 2012-2013 L-SMASH Works project
+ *
+ * Authors: Yusuke Nakamura <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *****************************************************************************/
+
+/* This file is available under an ISC license.
+ * However, when distributing its binary file, it will be under LGPL or GPL. */
+
+#include "lsmashsource.h"
+
+extern "C"
+{
+#include <libavcodec/avcodec.h>
+#include <libswscale/swscale.h>
+#include <libavutil/imgutils.h>
+#include <libavutil/mem.h>
+}
+
+#include "video_output.h"
+
+#if (LIBAVUTIL_VERSION_MICRO >= 100) && (LIBSWSCALE_VERSION_MICRO >= 100)
+#define FFMPEG_HIGH_DEPTH_SUPPORT 1
+#else
+#define FFMPEG_HIGH_DEPTH_SUPPORT 0
+#endif
+
+static void make_black_background_planar_yuv
+(
+ avxsynth::PVideoFrame &frame,
+ int bitdepth_minus_8
+)
+{
+ memset( frame->GetWritePtr( avxsynth::PLANAR_Y ), 0x00, frame->GetPitch( avxsynth::PLANAR_Y ) * frame->GetHeight( avxsynth::PLANAR_Y ) );
+ memset( frame->GetWritePtr( avxsynth::PLANAR_U ), 0x80, frame->GetPitch( avxsynth::PLANAR_U ) * frame->GetHeight( avxsynth::PLANAR_U ) );
+ memset( frame->GetWritePtr( avxsynth::PLANAR_V ), 0x80, frame->GetPitch( avxsynth::PLANAR_V ) * frame->GetHeight( avxsynth::PLANAR_V ) );
+}
+
+static void make_black_background_planar_yuv_interleaved
+(
+ avxsynth::PVideoFrame &frame,
+ int bitdepth_minus_8
+)
+{
+ memset( frame->GetWritePtr( avxsynth::PLANAR_Y ), 0x00, frame->GetPitch( avxsynth::PLANAR_Y ) * frame->GetHeight( avxsynth::PLANAR_Y ) );
+ uint8_t msb = (uint8_t)((0x80U << bitdepth_minus_8) >> 8);
+ int size = frame->GetPitch( avxsynth::PLANAR_U ) * frame->GetHeight( avxsynth::PLANAR_U );
+ for( int i = 0; i < size; i++ )
+ if( i & 1 )
+ {
+ *(frame->GetWritePtr( avxsynth::PLANAR_U ) + i) = msb;
+ *(frame->GetWritePtr( avxsynth::PLANAR_V ) + i) = msb;
+ }
+ else
+ {
+ *(frame->GetWritePtr( avxsynth::PLANAR_U ) + i) = 0x00;
+ *(frame->GetWritePtr( avxsynth::PLANAR_V ) + i) = 0x00;
+ }
+}
+
+static void make_black_background_packed_yuv422
+(
+ avxsynth::PVideoFrame &frame,
+ int bitdepth_minus_8
+)
+{
+ uint32_t *dst = (uint32_t *)frame->GetWritePtr();
+ int num_loops = frame->GetPitch() * frame->GetHeight() / 4;
+ for( int i = 0; i < num_loops; i++ )
+ *dst++ = 0x00800080;
+}
+
+static void make_black_background_packed_all_zero
+(
+ avxsynth::PVideoFrame &frame,
+ int bitdepth_minus_8
+)
+{
+ memset( frame->GetWritePtr(), 0x00, frame->GetPitch() * frame->GetHeight() );
+}
+
+/* This source filter always uses lines aligned to an address dividable by 32.
+ * Furthermore it seems Avisynth bulit-in BitBlt is slow.
+ * So, I think it's OK that we always use swscale instead. */
+static inline int convert_av_pixel_format
+(
+ struct SwsContext *sws_ctx,
+ int height,
+ AVFrame *av_frame,
+ AVPicture *av_picture
+)
+{
+ int ret = sws_scale( sws_ctx,
+ (const uint8_t * const *)av_frame->data, av_frame->linesize,
+ 0, height,
+ av_picture->data, av_picture->linesize );
+ return ret > 0 ? ret : -1;
+}
+
+static inline void as_assign_planar_yuv
+(
+ avxsynth::PVideoFrame &as_frame,
+ AVPicture *av_picture
+)
+{
+ av_picture->data [0] = as_frame->GetWritePtr( avxsynth::PLANAR_Y );
+ av_picture->data [1] = as_frame->GetWritePtr( avxsynth::PLANAR_U );
+ av_picture->data [2] = as_frame->GetWritePtr( avxsynth::PLANAR_V );
+ av_picture->linesize[0] = as_frame->GetPitch ( avxsynth::PLANAR_Y );
+ av_picture->linesize[1] = as_frame->GetPitch ( avxsynth::PLANAR_U );
+ av_picture->linesize[2] = as_frame->GetPitch ( avxsynth::PLANAR_V );
+}
+
+static int make_frame_planar_yuv
+(
+ lw_video_output_handler_t *vohp,
+ int height,
+ AVFrame *av_frame,
+ avxsynth::PVideoFrame &as_frame
+)
+{
+ AVPicture av_picture = { { NULL } };
+ as_assign_planar_yuv( as_frame, &av_picture );
+ return convert_av_pixel_format( vohp->scaler.sws_ctx, height, av_frame, &av_picture );
+}
+
+static int make_frame_planar_yuv_stacked
+(
+ lw_video_output_handler_t *vohp,
+ int height,
+ AVFrame *av_frame,
+ avxsynth::PVideoFrame &as_frame
+)
+{
+ AVPicture dst_picture = { { NULL } };
+ AVPicture src_picture = { { NULL } };
+ as_assign_planar_yuv( as_frame, &dst_picture );
+ lw_video_scaler_handler_t *vshp = &vohp->scaler;
+ as_video_output_handler_t *as_vohp = (as_video_output_handler_t *)vohp->private_handler;
+ if( vshp->input_pixel_format == vshp->output_pixel_format )
+ for( int i = 0; i < 3; i++ )
+ {
+ src_picture.data [i] = av_frame->data [i];
+ src_picture.linesize[i] = av_frame->linesize[i];
+ }
+ else
+ {
+ if( convert_av_pixel_format( vshp->sws_ctx, height, av_frame, &as_vohp->scaled ) < 0 )
+ return -1;
+ src_picture = as_vohp->scaled;
+ }
+ for( int i = 0; i < 3; i++ )
+ {
+ int dst_offset = 0;
+ int src_offset = 0;
+ int src_height = height >> (i ? as_vohp->sub_height : 0);
+ int linesize = MIN( src_picture.linesize[i], dst_picture.linesize[i] );
+ int lsb_offset = src_height * dst_picture.linesize[i];
+ for( int j = 0; j < src_height; j++ )
+ {
+ uint8_t *dst_msb = dst_picture.data[i] + dst_offset;
+ uint8_t *dst_lsb = dst_msb + lsb_offset;
+ uint8_t *src_lsb = src_picture.data[i] + src_offset;
+ uint8_t *src_msb = src_lsb + 1;
+ for( int k = 0; k < linesize; k++ )
+ {
+ *(dst_msb++) = *(src_msb);
+ src_msb += 2;
+ *(dst_lsb++) = *(src_lsb);
+ src_lsb += 2;
+ }
+ dst_offset += dst_picture.linesize[i];
+ src_offset += src_picture.linesize[i];
+ }
+ }
+ return 0;
+}
+
+static int make_frame_packed_yuv
+(
+ lw_video_output_handler_t *vohp,
+ int height,
+ AVFrame *av_frame,
+ avxsynth::PVideoFrame &as_frame
+)
+{
+ AVPicture av_picture = { { NULL } };
+ av_picture.data [0] = as_frame->GetWritePtr();
+ av_picture.linesize[0] = as_frame->GetPitch ();
+ return convert_av_pixel_format( vohp->scaler.sws_ctx, height, av_frame, &av_picture );
+}
+
+static int make_frame_packed_rgb
+(
+ lw_video_output_handler_t *vohp,
+ int height,
+ AVFrame *av_frame,
+ avxsynth::PVideoFrame &as_frame
+)
+{
+ AVPicture av_picture = { { NULL } };
+ av_picture.data [0] = as_frame->GetWritePtr() + as_frame->GetPitch() * (as_frame->GetHeight() - 1);
+ av_picture.linesize[0] = -as_frame->GetPitch();
+ return convert_av_pixel_format( vohp->scaler.sws_ctx, height, av_frame, &av_picture );
+}
+
+enum AVPixelFormat get_av_output_pixel_format
+(
+ const char *format_name
+)
+{
+ if( !format_name )
+ return AV_PIX_FMT_NONE;
+ static const struct
+ {
+ const char *format_name;
+ enum AVPixelFormat av_output_pixel_format;
+ } format_table[] =
+ {
+ { "YUV420P8", AV_PIX_FMT_YUV420P },
+ { "YUV422P8", AV_PIX_FMT_YUV422P },
+ { "YUV444P8", AV_PIX_FMT_YUV444P },
+ { "YUV410P8", AV_PIX_FMT_YUV410P },
+ { "YUV411P8", AV_PIX_FMT_YUV411P },
+ { "YUV440P8", AV_PIX_FMT_YUV440P },
+ { "YUV420P9", AV_PIX_FMT_YUV420P9LE },
+ { "YUV422P9", AV_PIX_FMT_YUV422P9LE },
+ { "YUV444P9", AV_PIX_FMT_YUV444P9LE },
+ { "YUV420P10", AV_PIX_FMT_YUV420P10LE },
+ { "YUV422P10", AV_PIX_FMT_YUV422P10LE },
+ { "YUV444P10", AV_PIX_FMT_YUV444P10LE },
+ { "YUV420P16", AV_PIX_FMT_YUV420P16LE },
+ { "YUV422P16", AV_PIX_FMT_YUV422P16LE },
+ { "YUV444P16", AV_PIX_FMT_YUV444P16LE },
+ { "YUY2", AV_PIX_FMT_YUYV422 },
+ { "RGB24", AV_PIX_FMT_BGR24 },
+#if FFMPEG_HIGH_DEPTH_SUPPORT
+ { "YUV420P12", AV_PIX_FMT_YUV420P12LE },
+ { "YUV420P14", AV_PIX_FMT_YUV420P14LE },
+ { "YUV422P12", AV_PIX_FMT_YUV422P12LE },
+ { "YUV422P14", AV_PIX_FMT_YUV422P14LE },
+ { "YUV444P12", AV_PIX_FMT_YUV444P12LE },
+ { "YUV444P14", AV_PIX_FMT_YUV444P14LE },
+#endif
+ { NULL, AV_PIX_FMT_NONE }
+ };
+ for( int i = 0; format_table[i].format_name; i++ )
+ if( strcasecmp( format_name, format_table[i].format_name ) == 0 )
+ return format_table[i].av_output_pixel_format;
+ return AV_PIX_FMT_NONE;
+}
+
+static int determine_colorspace_conversion
+(
+ lw_video_output_handler_t *vohp,
+ enum AVPixelFormat input_pixel_format,
+ enum AVPixelFormat output_pixel_format,
+ int *output_pixel_type
+)
+{
+ avoid_yuv_scale_conversion( &input_pixel_format );
+ const struct
+ {
+ enum AVPixelFormat input_pixel_format;
+ enum AVPixelFormat output_pixel_format;
+ int output_pixel_type;
+ int output_bitdepth_minus_8;
+ int output_sub_height;
+ } conversion_table[] =
+ {
+ { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P, avxsynth::VideoInfo::CS_I420, 0, 1 },
+ { AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, avxsynth::VideoInfo::CS_I420, 0, 1 },
+ { AV_PIX_FMT_NV21, AV_PIX_FMT_YUV420P, avxsynth::VideoInfo::CS_I420, 0, 1 },
+ { AV_PIX_FMT_YUV420P9LE, AV_PIX_FMT_YUV420P9LE, avxsynth::VideoInfo::CS_I420, 1, 1 },
+ { AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUV420P10LE, avxsynth::VideoInfo::CS_I420, 2, 1 },
+ { AV_PIX_FMT_YUV420P16LE, AV_PIX_FMT_YUV420P16LE, avxsynth::VideoInfo::CS_I420, 8, 1 },
+ { AV_PIX_FMT_YUYV422, AV_PIX_FMT_YUYV422, avxsynth::VideoInfo::CS_YUY2, 0, 0 },
+ { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUYV422, avxsynth::VideoInfo::CS_YUY2, 0, 0 },
+ { AV_PIX_FMT_UYVY422, AV_PIX_FMT_YUYV422, avxsynth::VideoInfo::CS_YUY2, 0, 0 },
+#if 0
+ { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P, avxsynth::VideoInfo::CS_YV16, 0, 0 },
+ { AV_PIX_FMT_YUV422P9LE, AV_PIX_FMT_YUV422P9LE, avxsynth::VideoInfo::CS_YV16, 1, 0 },
+ { AV_PIX_FMT_YUV422P10LE, AV_PIX_FMT_YUV422P10LE, avxsynth::VideoInfo::CS_YV16, 2, 0 },
+ { AV_PIX_FMT_YUV422P16LE, AV_PIX_FMT_YUV422P16LE, avxsynth::VideoInfo::CS_YV16, 8, 0 },
+ { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P, avxsynth::VideoInfo::CS_YV24, 0, 0 },
+ { AV_PIX_FMT_YUV444P9LE, AV_PIX_FMT_YUV444P9LE, avxsynth::VideoInfo::CS_YV24, 1, 0 },
+ { AV_PIX_FMT_YUV444P10LE, AV_PIX_FMT_YUV444P10LE, avxsynth::VideoInfo::CS_YV24, 2, 0 },
+ { AV_PIX_FMT_YUV444P16LE, AV_PIX_FMT_YUV444P16LE, avxsynth::VideoInfo::CS_YV24, 8, 0 },
+ { AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV410P, avxsynth::VideoInfo::CS_YUV9, 0, 2 },
+ { AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV411P, avxsynth::VideoInfo::CS_YV411, 0, 0 },
+ { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8, avxsynth::VideoInfo::CS_Y8, 0, 0 },
+#endif
+ { AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, avxsynth::VideoInfo::CS_BGR24, 0, 0 },
+ { AV_PIX_FMT_BGR24, AV_PIX_FMT_BGR24, avxsynth::VideoInfo::CS_BGR24, 0, 0 },
+ { AV_PIX_FMT_ARGB, AV_PIX_FMT_BGRA, avxsynth::VideoInfo::CS_BGR32, 0, 0 },
+ { AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, avxsynth::VideoInfo::CS_BGR32, 0, 0 },
+ { AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA, avxsynth::VideoInfo::CS_BGR32, 0, 0 },
+ { AV_PIX_FMT_BGRA, AV_PIX_FMT_BGRA, avxsynth::VideoInfo::CS_BGR32, 0, 0 },
+#if FFMPEG_HIGH_DEPTH_SUPPORT
+ { AV_PIX_FMT_YUV420P12LE, AV_PIX_FMT_YUV420P12LE, avxsynth::VideoInfo::CS_I420, 4, 1 },
+ { AV_PIX_FMT_YUV420P14LE, AV_PIX_FMT_YUV420P14LE, avxsynth::VideoInfo::CS_I420, 6, 1 },
+#if 0
+ { AV_PIX_FMT_YUV422P12LE, AV_PIX_FMT_YUV422P12LE, avxsynth::VideoInfo::CS_YV16, 4, 0 },
+ { AV_PIX_FMT_YUV422P14LE, AV_PIX_FMT_YUV422P14LE, avxsynth::VideoInfo::CS_YV16, 6, 0 },
+ { AV_PIX_FMT_YUV444P12LE, AV_PIX_FMT_YUV444P12LE, avxsynth::VideoInfo::CS_YV24, 4, 0 },
+ { AV_PIX_FMT_YUV444P14LE, AV_PIX_FMT_YUV444P14LE, avxsynth::VideoInfo::CS_YV24, 6, 0 },
+#endif
+#endif
+ { AV_PIX_FMT_NONE, AV_PIX_FMT_NONE, avxsynth::VideoInfo::CS_UNKNOWN, 0, 0 }
+ };
+ lw_video_scaler_handler_t *vshp = &vohp->scaler;
+ as_video_output_handler_t *as_vohp = (as_video_output_handler_t *)vohp->private_handler;
+ as_vohp->bitdepth_minus_8 = 0;
+ vshp->output_pixel_format = output_pixel_format;
+ int i = 0;
+ if( vshp->output_pixel_format == AV_PIX_FMT_NONE )
+ {
+ for( i = 0; conversion_table[i].input_pixel_format != AV_PIX_FMT_NONE; i++ )
+ if( conversion_table[i].input_pixel_format == input_pixel_format )
+ {
+ vshp->output_pixel_format = conversion_table[i].output_pixel_format;
+ break;
+ }
+ }
+ else
+ {
+ for( i = 0; conversion_table[i].input_pixel_format != AV_PIX_FMT_NONE; i++ )
+ if( conversion_table[i].output_pixel_format == vshp->output_pixel_format )
+ break;
+ }
+ *output_pixel_type = conversion_table[i].output_pixel_type;
+ as_vohp->bitdepth_minus_8 = conversion_table[i].output_bitdepth_minus_8;
+ as_vohp->sub_height = conversion_table[i].output_sub_height;
+ switch( vshp->output_pixel_format )
+ {
+ case AV_PIX_FMT_YUV420P : /* planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) */
+ case AV_PIX_FMT_YUV422P : /* planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) */
+ case AV_PIX_FMT_YUV444P : /* planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) */
+ case AV_PIX_FMT_YUV410P : /* planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) */
+ case AV_PIX_FMT_YUV411P : /* planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) */
+ as_vohp->make_black_background = make_black_background_planar_yuv;
+ as_vohp->make_frame = make_frame_planar_yuv;
+ return 0;
+ case AV_PIX_FMT_YUYV422 : /* packed YUV 4:2:2, 16bpp */
+ as_vohp->make_black_background = make_black_background_packed_yuv422;
+ as_vohp->make_frame = make_frame_packed_yuv;
+ return 0;
+ case AV_PIX_FMT_YUV420P9LE : /* planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian */
+ case AV_PIX_FMT_YUV420P10LE : /* planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian */
+ case AV_PIX_FMT_YUV420P16LE : /* planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian */
+ case AV_PIX_FMT_YUV422P9LE : /* planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian */
+ case AV_PIX_FMT_YUV422P10LE : /* planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian */
+ case AV_PIX_FMT_YUV422P16LE : /* planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian */
+ case AV_PIX_FMT_YUV444P9LE : /* planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian */
+ case AV_PIX_FMT_YUV444P10LE : /* planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian */
+ case AV_PIX_FMT_YUV444P16LE : /* planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian */
+#if FFMPEG_HIGH_DEPTH_SUPPORT
+ case AV_PIX_FMT_YUV420P12LE :
+ case AV_PIX_FMT_YUV420P14LE :
+ case AV_PIX_FMT_YUV422P12LE :
+ case AV_PIX_FMT_YUV422P14LE :
+ case AV_PIX_FMT_YUV444P12LE :
+ case AV_PIX_FMT_YUV444P14LE :
+#endif
+ if( as_vohp->stacked_format )
+ {
+ as_vohp->make_black_background = make_black_background_planar_yuv;
+ as_vohp->make_frame = make_frame_planar_yuv_stacked;
+ }
+ else
+ {
+ as_vohp->make_black_background = make_black_background_planar_yuv_interleaved;
+ as_vohp->make_frame = make_frame_planar_yuv;
+ }
+ return 0;
+ case AV_PIX_FMT_GRAY8 : /* Y, 8bpp */
+ as_vohp->make_black_background = make_black_background_packed_all_zero;
+ as_vohp->make_frame = make_frame_packed_yuv;
+ return 0;
+ case AV_PIX_FMT_BGR24 : /* packed RGB 8:8:8, 24bpp, BGRBGR... */
+ case AV_PIX_FMT_BGRA : /* packed BGRA 8:8:8:8, 32bpp, BGRABGRA... */
+ as_vohp->make_black_background = make_black_background_packed_all_zero;
+ as_vohp->make_frame = make_frame_packed_rgb;
+ return 0;
+ default :
+ as_vohp->make_black_background = NULL;
+ as_vohp->make_frame = NULL;
+ return -1;
+ }
+}
+
+int make_frame
+(
+ lw_video_output_handler_t *vohp,
+ AVCodecContext *ctx,
+ AVFrame *av_frame,
+ avxsynth::PVideoFrame &as_frame,
+ avxsynth::IScriptEnvironment *env
+)
+{
+ lw_video_scaler_handler_t *vshp = &vohp->scaler;
+ if( !vshp->enabled && av_frame->opaque )
+ {
+ /* Render a video frame from the decoder directly. */
+ as_video_buffer_handler_t *as_vbhp = (as_video_buffer_handler_t *)av_frame->opaque;
+ as_frame = as_vbhp->as_frame_buffer;
+ return 0;
+ }
+ /* Convert pixel format. We don't change the presentation resolution. */
+ as_video_output_handler_t *as_vohp = (as_video_output_handler_t *)vohp->private_handler;
+ enum AVPixelFormat *input_pixel_format = (enum AVPixelFormat *)&av_frame->format;
+ int yuv_range = avoid_yuv_scale_conversion( input_pixel_format );
+ if( !vshp->sws_ctx
+ || vshp->input_width != ctx->width
+ || vshp->input_height != ctx->height
+ || vshp->input_pixel_format != *input_pixel_format
+ || vshp->input_colorspace != ctx->colorspace
+ || vshp->input_yuv_range != yuv_range )
+ {
+ /* Update scaler. */
+ vshp->sws_ctx = update_scaler_configuration( vshp->sws_ctx, vshp->flags,
+ ctx->width, ctx->height,
+ *input_pixel_format, vshp->output_pixel_format,
+ ctx->colorspace, yuv_range );
+ if( !vshp->sws_ctx )
+ return -1;
+ vshp->input_width = ctx->width;
+ vshp->input_height = ctx->height;
+ vshp->input_pixel_format = *input_pixel_format;
+ vshp->input_colorspace = ctx->colorspace;
+ vshp->input_yuv_range = yuv_range;
+ }
+ /* Render a video frame through the scaler from the decoder. */
+ as_frame = env->NewVideoFrame( *as_vohp->vi, 32 );
+ if( vohp->output_width != (ctx->width << (as_vohp->bitdepth_minus_8 && !as_vohp->stacked_format ? 1 : 0))
+ || vohp->output_height != (ctx->height << (as_vohp->bitdepth_minus_8 && as_vohp->stacked_format ? 1 : 0)) )
+ as_vohp->make_black_background( as_frame, as_vohp->bitdepth_minus_8 );
+ return as_vohp->make_frame( vohp, ctx->height, av_frame, as_frame );
+}
+
+static int as_check_dr_available
+(
+ AVCodecContext *ctx,
+ enum AVPixelFormat pixel_format,
+ int stacked_format
+)
+{
+ if( !(ctx->codec->capabilities & CODEC_CAP_DR1) )
+ return 0;
+ static const struct
+ {
+ enum AVPixelFormat pixel_format;
+ int stacked_support;
+ } dr_support_table[] =
+ {
+ { AV_PIX_FMT_YUV420P, 0 },
+ { AV_PIX_FMT_YUV420P9LE, 1 },
+ { AV_PIX_FMT_YUV420P10LE, 1 },
+ { AV_PIX_FMT_YUV420P16LE, 1 },
+ { AV_PIX_FMT_YUV422P, 0 },
+ { AV_PIX_FMT_YUV422P9LE, 1 },
+ { AV_PIX_FMT_YUV422P10LE, 1 },
+ { AV_PIX_FMT_YUV422P16LE, 1 },
+ { AV_PIX_FMT_YUV444P, 0 },
+ { AV_PIX_FMT_YUV444P9LE, 1 },
+ { AV_PIX_FMT_YUV444P10LE, 1 },
+ { AV_PIX_FMT_YUV444P16LE, 1 },
+ { AV_PIX_FMT_YUV410P, 0 },
+ { AV_PIX_FMT_YUV411P, 0 },
+ { AV_PIX_FMT_YUYV422, 0 },
+ { AV_PIX_FMT_GRAY8, 0 },
+ { AV_PIX_FMT_BGR24, 0 },
+ { AV_PIX_FMT_BGRA, 0 },
+#if FFMPEG_HIGH_DEPTH_SUPPORT
+ { AV_PIX_FMT_YUV420P12LE, 1 },
+ { AV_PIX_FMT_YUV420P14LE, 1 },
+ { AV_PIX_FMT_YUV422P12LE, 1 },
+ { AV_PIX_FMT_YUV422P14LE, 1 },
+ { AV_PIX_FMT_YUV444P12LE, 1 },
+ { AV_PIX_FMT_YUV444P14LE, 1 },
+#endif
+ { AV_PIX_FMT_NONE, 0 }
+ };
+ for( int i = 0; dr_support_table[i].pixel_format != AV_PIX_FMT_NONE; i++ )
+ if( dr_support_table[i].pixel_format == pixel_format )
+ return !(dr_support_table[i].stacked_support && stacked_format);
+ return 0;
+}
+
+static void as_video_release_buffer_handler
+(
+ void *opaque,
+ uint8_t *data
+)
+{
+ as_video_buffer_handler_t *as_vbhp = (as_video_buffer_handler_t *)opaque;
+ delete as_vbhp;
+}
+
+static void as_video_unref_buffer_handler
+(
+ void *opaque,
+ uint8_t *data
+)
+{
+ /* Decrement the reference-counter to the video buffer handler by 1.
+ * Delete it by as_video_release_buffer_handler() if there are no reference to it i.e. the reference-counter equals zero. */
+ AVBufferRef *as_buffer_ref = (AVBufferRef *)opaque;
+ av_buffer_unref( &as_buffer_ref );
+}
+
+static int as_video_get_buffer
+(
+ AVCodecContext *ctx,
+ AVFrame *av_frame,
+ int flags
+)
+{
+ lw_video_output_handler_t *lw_vohp = (lw_video_output_handler_t *)ctx->opaque;
+ as_video_output_handler_t *as_vohp = (as_video_output_handler_t *)lw_vohp->private_handler;
+ lw_video_scaler_handler_t *vshp = &lw_vohp->scaler;
+ vshp->enabled = 0;
+ enum AVPixelFormat pix_fmt = ctx->pix_fmt;
+ avoid_yuv_scale_conversion( &pix_fmt );
+ if( vshp->input_pixel_format != pix_fmt
+ || !as_check_dr_available( ctx, pix_fmt, as_vohp->stacked_format ) )
+ vshp->enabled = 1;
+ if( vshp->enabled )
+ return avcodec_default_get_buffer2( ctx, av_frame, 0 );
+ /* New AviSynth video frame buffer. */
+ as_video_buffer_handler_t *as_vbhp = new as_video_buffer_handler_t;
+ if( !as_vbhp )
+ {
+ av_frame_unref( av_frame );
+ return AVERROR( ENOMEM );
+ }
+ av_frame->opaque = as_vbhp;
+ as_vbhp->as_frame_buffer = as_vohp->env->NewVideoFrame( *as_vohp->vi, 32 );
+ int aligned_width = ctx->width << (as_vohp->bitdepth_minus_8 ? 1 : 0);
+ int aligned_height = ctx->height;
+ avcodec_align_dimensions2( ctx, &aligned_width, &aligned_height, av_frame->linesize );
+ if( lw_vohp->output_width != aligned_width || lw_vohp->output_height != aligned_height )
+ as_vohp->make_black_background( as_vbhp->as_frame_buffer, as_vohp->bitdepth_minus_8 );
+ /* Create frame buffers for the decoder.
+ * The callback as_video_release_buffer_handler() shall be called when no reference to the video buffer handler is present.
+ * The callback as_video_unref_buffer_handler() decrements the reference-counter by 1. */
+ memset( av_frame->buf, 0, sizeof(av_frame->buf) );
+ memset( av_frame->data, 0, sizeof(av_frame->data) );
+ memset( av_frame->linesize, 0, sizeof(av_frame->linesize) );
+ AVBufferRef *as_buffer_handler = av_buffer_create( NULL, 0, as_video_release_buffer_handler, as_vbhp, 0 );
+ if( !as_buffer_handler )
+ {
+ delete as_vbhp;
+ av_frame_unref( av_frame );
+ return AVERROR( ENOMEM );
+ }
+#define CREATE_PLANE_BUFFER( PLANE, PLANE_ID ) \
+ do \
+ { \
+ AVBufferRef *as_buffer_ref = av_buffer_ref( as_buffer_handler ); \
+ if( !as_buffer_ref ) \
+ { \
+ av_buffer_unref( &as_buffer_handler ); \
+ goto fail; \
+ } \
+ av_frame->linesize[PLANE] = as_vbhp->as_frame_buffer->GetPitch( PLANE_ID ); \
+ int as_plane_size = as_vbhp->as_frame_buffer->GetHeight( PLANE_ID ) \
+ * av_frame->linesize[PLANE]; \
+ av_frame->buf[PLANE] = av_buffer_create( as_vbhp->as_frame_buffer->GetWritePtr( PLANE_ID ), \
+ as_plane_size, \
+ as_video_unref_buffer_handler, \
+ as_buffer_ref, \
+ 0 ); \
+ if( !av_frame->buf[PLANE] ) \
+ goto fail; \
+ av_frame->data[PLANE] = av_frame->buf[PLANE]->data; \
+ } while( 0 )
+ if( as_vohp->vi->pixel_type & avxsynth::VideoInfo::CS_INTERLEAVED )
+ CREATE_PLANE_BUFFER( 0, );
+ else
+ for( int i = 0; i < 3; i++ )
+ {
+ static const int as_plane[3] = { avxsynth::PLANAR_Y, avxsynth::PLANAR_U, avxsynth::PLANAR_V };
+ CREATE_PLANE_BUFFER( i, as_plane[i] );
+ }
+ /* Here, a variable 'as_buffer_handler' itself is not referenced by any pointer. */
+ av_buffer_unref( &as_buffer_handler );
+#undef CREATE_PLANE_BUFFER
+ av_frame->nb_extended_buf = 0;
+ av_frame->extended_data = av_frame->data;
+ return 0;
+fail:
+ av_frame_unref( av_frame );
+ av_buffer_unref( &as_buffer_handler );
+ return AVERROR( ENOMEM );
+}
+
+void as_free_video_output_handler
+(
+ void *private_handler
+)
+{
+ as_video_output_handler_t *as_vohp = (as_video_output_handler_t *)private_handler;
+ if( !as_vohp )
+ return;
+ if( as_vohp->scaled.data[0] )
+ av_freep( &as_vohp->scaled.data[0] );
+ free( as_vohp );
+}
+
+func_get_buffer_t *as_setup_video_rendering
+(
+ lw_video_output_handler_t *vohp,
+ AVCodecContext *ctx,
+ const char *filter_name,
+ int direct_rendering,
+ int stacked_format,
+ enum AVPixelFormat output_pixel_format,
+ int output_width,
+ int output_height
+)
+{
+ as_video_output_handler_t *as_vohp = (as_video_output_handler_t *)vohp->private_handler;
+ avxsynth::IScriptEnvironment *env = as_vohp->env;
+ avxsynth::VideoInfo *vi = as_vohp->vi;
+ as_vohp->stacked_format = stacked_format;
+ if( determine_colorspace_conversion( vohp, ctx->pix_fmt, output_pixel_format, &vi->pixel_type ) < 0 )
+ env->ThrowError( "%s: %s is not supported", filter_name, av_get_pix_fmt_name( ctx->pix_fmt ) );
+ vi->width = output_width << (as_vohp->bitdepth_minus_8 && !as_vohp->stacked_format ? 1 : 0);
+ vi->height = output_height << (as_vohp->bitdepth_minus_8 && as_vohp->stacked_format ? 1 : 0);
+ enum AVPixelFormat input_pixel_format = ctx->pix_fmt;
+ avoid_yuv_scale_conversion( &input_pixel_format );
+ direct_rendering &= as_check_dr_available( ctx, input_pixel_format, as_vohp->stacked_format );
+ lw_video_scaler_handler_t *vshp = &vohp->scaler;
+ if( initialize_scaler_handler( vshp, ctx, !direct_rendering, SWS_FAST_BILINEAR, vshp->output_pixel_format ) < 0 )
+ env->ThrowError( "%s: failed to initialize scaler handler.", filter_name );
+ /* Allocate temporally scaled image if stacked format could be required.*/
+ if( as_vohp->stacked_format
+ && av_image_alloc( as_vohp->scaled.data, as_vohp->scaled.linesize,
+ vi->width, vi->height, vshp->output_pixel_format, 32 ) < 0 )
+ env->ThrowError( "%s: failed to allocate temporally scaled image.", filter_name );
+ /* Set up direct rendering if available. */
+ if( direct_rendering )
+ {
+ /* Align output width and height for direct rendering. */
+ int linesize_align[AV_NUM_DATA_POINTERS];
+ input_pixel_format = ctx->pix_fmt;
+ ctx->pix_fmt = vohp->scaler.output_pixel_format;
+ avcodec_align_dimensions2( ctx, &vi->width, &vi->height, linesize_align );
+ ctx->pix_fmt = input_pixel_format;
+ /* Set up custom get_buffer() for direct rendering if available. */
+ ctx->get_buffer2 = as_video_get_buffer;
+ ctx->opaque = vohp;
+ ctx->flags |= CODEC_FLAG_EMU_EDGE;
+ }
+ vohp->output_width = vi->width;
+ vohp->output_height = vi->height;
+ return ctx->get_buffer2;
+}
diff --git a/AvxSynth/video_output.h b/AvxSynth/video_output.h
new file mode 100644
index 0000000..4dc6676
--- /dev/null
+++ b/AvxSynth/video_output.h
@@ -0,0 +1,87 @@
+/*****************************************************************************
+ * video_output.h
+ *****************************************************************************
+ * Copyright (C) 2012-2013 L-SMASH Works project
+ *
+ * Authors: Yusuke Nakamura <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *****************************************************************************/
+
+/* This file is available under an ISC license.
+ * However, when distributing its binary file, it will be under LGPL or GPL. */
+
+#include "../common/video_output.h"
+
+typedef void func_make_black_background
+(
+ avxsynth::PVideoFrame &frame,
+ int bitdepth_minus_8
+);
+
+typedef int func_make_frame
+(
+ lw_video_output_handler_t *vohp,
+ int height,
+ AVFrame *av_frame,
+ avxsynth::PVideoFrame &as_frame
+);
+
+typedef struct
+{
+ func_make_black_background *make_black_background;
+ func_make_frame *make_frame;
+ avxsynth::IScriptEnvironment *env;
+ avxsynth::VideoInfo *vi;
+ int bitdepth_minus_8;
+ /* for stacked format */
+ int stacked_format;
+ int sub_height;
+ AVPicture scaled;
+} as_video_output_handler_t;
+
+typedef struct
+{
+ avxsynth::PVideoFrame as_frame_buffer;
+} as_video_buffer_handler_t;
+
+enum AVPixelFormat get_av_output_pixel_format
+(
+ const char *format_name
+);
+
+int make_frame
+(
+ lw_video_output_handler_t *vohp,
+ AVCodecContext *ctx,
+ AVFrame *av_frame,
+ avxsynth::PVideoFrame &as_frame,
+ avxsynth::IScriptEnvironment *env
+);
+
+void as_free_video_output_handler
+(
+ void *private_handler
+);
+
+func_get_buffer_t *as_setup_video_rendering
+(
+ lw_video_output_handler_t *vohp,
+ AVCodecContext *ctx,
+ const char *filter_name,
+ int direct_rendering,
+ int stacked_format,
+ enum AVPixelFormat output_pixel_format,
+ int output_width,
+ int output_height
+);
diff --git a/AvxSynth/windowsPorts/WinDefLinux.h b/AvxSynth/windowsPorts/WinDefLinux.h
new file mode 100644
index 0000000..20090e3
--- /dev/null
+++ b/AvxSynth/windowsPorts/WinDefLinux.h
@@ -0,0 +1,20 @@
+#ifndef __WINDEF_LINUX_H__
+#define __WINDEF_LINUX_H__
+
+namespace avxsynth {
+
+/////////////////////////////////
+// Copied from Windows WinDef.h
+/////////////////////////////////
+
+typedef struct tagRECT {
+ LONG left;
+ LONG top;
+ LONG right;
+ LONG bottom;
+} RECT, *LPRECT;
+
+
+}; // namespace avxsynth
+
+#endif // __WINDEF_LINUX_H__
diff --git a/AvxSynth/windowsPorts/WinNTLinux.h b/AvxSynth/windowsPorts/WinNTLinux.h
new file mode 100644
index 0000000..a82ccdc
--- /dev/null
+++ b/AvxSynth/windowsPorts/WinNTLinux.h
@@ -0,0 +1,74 @@
+#ifndef __WINNT_LINUX_H__
+#define __WINNT_LINUX_H__
+
+#include "basicDataTypeConversions.h"
+
+namespace avxsynth {
+
+/////////////////////////////////
+// Copied from Windows WinNT.h
+/////////////////////////////////
+
+#define NTSTATUS LONG
+#define STATUS_NO_MEMORY ((NTSTATUS)0xC0000017L) // winnt
+#define STATUS_NONCONTINUABLE_EXCEPTION ((NTSTATUS)0xC0000025L) // winnt
+#define STATUS_INVALID_DISPOSITION ((NTSTATUS)0xC0000026L) // winnt
+#define STATUS_ACCESS_VIOLATION 0xC0000005
+#define STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008C
+#define STATUS_BAD_COMPRESSION_BUFFER 0xC0000242
+#define STATUS_BREAKPOINT 0x80000003
+#define STATUS_CALLBACK_POP_STACK 0xC0000423
+#define STATUS_DATATYPE_MISALIGNMENT 0x80000002
+#define STATUS_FLOAT_DENORMAL_OPERAND 0xC000008D
+#define STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008E
+#define STATUS_FLOAT_INEXACT_RESULT 0xC000008F
+#define STATUS_FLOAT_INVALID_OPERATION 0xC0000090
+#define STATUS_FLOAT_OVERFLOW 0xC0000091
+#define STATUS_FLOAT_STACK_CHECK 0xC0000092
+#define STATUS_FLOAT_UNDERFLOW 0xC0000093
+#define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4
+#define STATUS_FLOAT_MULTIPLE_TRAPS 0xC00002B5
+#define STATUS_GUARD_PAGE_VIOLATION 0x80000001
+#define STATUS_ILLEGAL_FLOAT_CONTEXT 0xC000014A
+#define STATUS_ILLEGAL_INSTRUCTION 0xC000001D
+#define STATUS_INSTRUCTION_MISALIGNMENT 0xC00000AA
+#define STATUS_INVALID_HANDLE 0xC0000008
+#define STATUS_INVALID_LOCK_SEQUENCE 0xC000001E
+#define STATUS_INVALID_OWNER 0xC000005A
+#define STATUS_INVALID_PARAMETER 0xC000000D
+#define STATUS_INVALID_PARAMETER_1 0xC00000EF
+#define STATUS_INVALID_SYSTEM_SERVICE 0xC000001C
+#define STATUS_INVALID_THREAD 0xC000071C
+#define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094
+#define STATUS_INTEGER_OVERFLOW 0xC0000095
+#define STATUS_IN_PAGE_ERROR 0xC0000006
+#define STATUS_KERNEL_APC 0x0100
+#define STATUS_LONGJUMP 0x80000026
+#define STATUS_NO_CALLBACK_ACTIVE 0xC0000258
+#define STATUS_NO_EVENT_PAIR 0xC000014E
+#define STATUS_PRIVILEGED_INSTRUCTION 0xC0000096
+#define STATUS_SINGLE_STEP 0x80000004
+#define STATUS_STACK_BUFFER_OVERRUN 0xC0000409
+#define STATUS_STACK_OVERFLOW 0xC00000FD
+#define STATUS_SUCCESS 0x0000
+#define STATUS_THREAD_IS_TERMINATING 0xC000004B
+#define STATUS_TIMEOUT 0x0102
+#define STATUS_UNWIND 0xC0000027
+#define STATUS_UNWIND_CONSOLIDATE 0x80000029
+#define STATUS_USER_APC 0x00C0H
+#define STATUS_WAKE_SYSTEM_DEBUGGER 0x80000007
+
+#define EXCEPTION_MAXIMUM_PARAMETERS 15 // maximum number of exception parameters
+typedef struct _EXCEPTION_RECORD {
+ DWORD ExceptionCode;
+ DWORD ExceptionFlags;
+ struct _EXCEPTION_RECORD *ExceptionRecord;
+ PVOID ExceptionAddress;
+ DWORD NumberParameters;
+ ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
+} EXCEPTION_RECORD;
+
+
+}; // namespace avxsynth
+
+#endif // __WINNT_LINUX_H__
diff --git a/AvxSynth/windowsPorts/basicDataTypeConversions.h b/AvxSynth/windowsPorts/basicDataTypeConversions.h
new file mode 100644
index 0000000..b757ee7
--- /dev/null
+++ b/AvxSynth/windowsPorts/basicDataTypeConversions.h
@@ -0,0 +1,85 @@
+#ifndef __DATA_TYPE_CONVERSIONS_H__
+#define __DATA_TYPE_CONVERSIONS_H__
+
+#include <stdint.h>
+#include <wchar.h>
+
+#ifdef __cplusplus
+namespace avxsynth {
+#endif // __cplusplus
+
+typedef int64_t __int64;
+typedef int32_t __int32;
+#ifdef __cplusplus
+typedef bool BOOL;
+#else
+typedef uint32_t BOOL;
+#endif // __cplusplus
+typedef void* HMODULE;
+typedef void* LPVOID;
+typedef void* PVOID;
+typedef PVOID HANDLE;
+typedef HANDLE HWND;
+typedef HANDLE HINSTANCE;
+typedef void* HDC;
+typedef void* HBITMAP;
+typedef void* HICON;
+typedef void* HFONT;
+typedef void* HGDIOBJ;
+typedef void* HBRUSH;
+typedef void* HMMIO;
+typedef void* HACMSTREAM;
+typedef void* HACMDRIVER;
+typedef void* HIC;
+typedef void* HACMOBJ;
+typedef HACMSTREAM* LPHACMSTREAM;
+typedef void* HACMDRIVERID;
+typedef void* LPHACMDRIVER;
+typedef unsigned char BYTE;
+typedef BYTE* LPBYTE;
+typedef char TCHAR;
+typedef TCHAR* LPTSTR;
+typedef const TCHAR* LPCTSTR;
+typedef char* LPSTR;
+typedef LPSTR LPOLESTR;
+typedef const char* LPCSTR;
+typedef LPCSTR LPCOLESTR;
+typedef wchar_t WCHAR;
+typedef unsigned short WORD;
+typedef unsigned int UINT;
+typedef UINT MMRESULT;
+typedef uint32_t DWORD;
+typedef DWORD COLORREF;
+typedef DWORD FOURCC;
+typedef DWORD HRESULT;
+typedef DWORD* LPDWORD;
+typedef DWORD* DWORD_PTR;
+typedef int32_t LONG;
+typedef int32_t* LONG_PTR;
+typedef LONG_PTR LRESULT;
+typedef uint32_t ULONG;
+typedef uint32_t* ULONG_PTR;
+//typedef __int64_t intptr_t;
+typedef uint64_t _fsize_t;
+
+
+//
+// Structures
+//
+
+typedef struct _GUID {
+ DWORD Data1;
+ WORD Data2;
+ WORD Data3;
+ BYTE Data4[8];
+} GUID;
+
+typedef GUID REFIID;
+typedef GUID CLSID;
+typedef CLSID* LPCLSID;
+typedef GUID IID;
+
+#ifdef __cplusplus
+}; // namespace avxsynth
+#endif // __cplusplus
+#endif // __DATA_TYPE_CONVERSIONS_H__
diff --git a/AvxSynth/windowsPorts/excptLinux.h b/AvxSynth/windowsPorts/excptLinux.h
new file mode 100644
index 0000000..4274e4f
--- /dev/null
+++ b/AvxSynth/windowsPorts/excptLinux.h
@@ -0,0 +1,21 @@
+#ifndef __EXCPT_LINUX_H__
+#define __EXCPT_LINUX_H__
+
+namespace avxsynth {
+
+/////////////////////////////////
+// Copied from Windows excpt.h
+/////////////////////////////////
+
+typedef enum _EXCEPTION_DISPOSITION {
+ ExceptionContinueExecution,
+ ExceptionContinueSearch,
+ ExceptionNestedException,
+ ExceptionCollidedUnwind
+} EXCEPTION_DISPOSITION;
+
+
+
+}; // namespace avxsynth
+
+#endif // __EXCPT_LINUX_H__
diff --git a/AvxSynth/windowsPorts/windows2linux.h b/AvxSynth/windowsPorts/windows2linux.h
new file mode 100644
index 0000000..5476afe
--- /dev/null
+++ b/AvxSynth/windowsPorts/windows2linux.h
@@ -0,0 +1,77 @@
+#ifndef __WINDOWS2LINUX_H__
+#define __WINDOWS2LINUX_H__
+
+/*
+ * LINUX SPECIFIC DEFINITIONS
+*/
+//
+// Data types conversions
+//
+#include <stdlib.h>
+#include <string.h>
+#include "basicDataTypeConversions.h"
+
+#ifdef __cplusplus
+namespace avxsynth {
+#endif // __cplusplus
+//
+// purposefully define the following MSFT definitions
+// to mean nothing (as they do not mean anything on Linux)
+//
+#define __stdcall
+#define __cdecl
+#define noreturn
+#define __declspec(x)
+#define STDAPI extern "C" HRESULT
+#define STDMETHODIMP HRESULT __stdcall
+#define STDMETHODIMP_(x) x __stdcall
+
+#define STDMETHOD(x) virtual HRESULT x
+#define STDMETHOD_(a, x) virtual a x
+
+#ifndef TRUE
+#define TRUE true
+#endif
+
+#ifndef FALSE
+#define FALSE false
+#endif
+
+#define S_OK (0x00000000)
+#define S_FALSE (0x00000001)
+#define E_NOINTERFACE (0X80004002)
+#define E_POINTER (0x80004003)
+#define E_FAIL (0x80004005)
+#define E_OUTOFMEMORY (0x8007000E)
+
+#define INVALID_HANDLE_VALUE ((HANDLE)((LONG_PTR)-1))
+#define FAILED(hr) ((hr) & 0x80000000)
+#define SUCCEEDED(hr) (!FAILED(hr))
+
+
+//
+// Functions
+//
+#define MAKEDWORD(a,b,c,d) ((a << 24) | (b << 16) | (c << 8) | (d))
+#define MAKEWORD(a,b) ((a << 8) | (b))
+
+#define lstrlen strlen
+#define lstrcpy strcpy
+#define lstrcmpi strcasecmp
+#define _stricmp strcasecmp
+#define InterlockedIncrement(x) __sync_fetch_and_add((x), 1)
+#define InterlockedDecrement(x) __sync_fetch_and_sub((x), 1)
+// Windows uses (new, old) ordering but GCC has (old, new)
+#define InterlockedCompareExchange(x,y,z) __sync_val_compare_and_swap(x,z,y)
+
+#define UInt32x32To64(a, b) ( (uint64_t) ( ((uint64_t)((uint32_t)(a))) * ((uint32_t)(b)) ) )
+#define Int64ShrlMod32(a, b) ( (uint64_t) ( (uint64_t)(a) >> (b) ) )
+#define Int32x32To64(a, b) ((__int64)(((__int64)((long)(a))) * ((long)(b))))
+
+#define MulDiv(nNumber, nNumerator, nDenominator) (int32_t) (((int64_t) (nNumber) * (int64_t) (nNumerator) + (int64_t) ((nDenominator)/2)) / (int64_t) (nDenominator))
+
+#ifdef __cplusplus
+}; // namespace avxsynth
+#endif // __cplusplus
+
+#endif // __WINDOWS2LINUX_H__
--
1.8.1.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment