Last active
December 18, 2015 13:59
-
-
Save qyot27/5794294 to your computer and use it in GitHub Desktop.
Support for AvxSynth
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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